home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / mac / tkMacMenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  116.8 KB  |  3,968 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkMacMenu.c --
  3.  *
  4.  *    This module implements the Mac-platform specific features of menus.
  5.  *
  6.  * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * SCCS: @(#) tkMacMenu.c 1.102 97/08/11 10:21:07
  12.  */
  13.  
  14. #include <Menus.h>
  15. #include <OSUtils.h>
  16. #include <Palettes.h>
  17. #include <Resources.h>
  18. #include <string.h>
  19. #include <ToolUtils.h>
  20. #include <Balloons.h>
  21. #undef Status
  22. #include <Devices.h>
  23. #include "tkMenu.h"
  24. #include "tkMacInt.h"
  25. #include "tkMenuButton.h"
  26.  
  27. typedef struct MacMenu {
  28.     MenuHandle menuHdl;        /* The Menu Manager data structure. */
  29.     Rect menuRect;        /* The rectangle as calculated in the
  30.                      * MDEF. This is used to figure ou the
  31.                      * clipping rgn before we push
  32.                      * the <<MenuSelect>> virtual binding
  33.                      * through. */
  34. } MacMenu;
  35.  
  36. /*
  37.  * Various geometry definitions:
  38.  */
  39.  
  40. #define CASCADE_ARROW_HEIGHT     10
  41. #define CASCADE_ARROW_WIDTH     8
  42. #define DECORATION_BORDER_WIDTH 2
  43. #define MAC_MARGIN_WIDTH     8
  44.  
  45. /*
  46.  * The following are constants relating to the SICNs used for drawing the MDEF.
  47.  */
  48.  
  49. #define SICN_RESOURCE_NUMBER        128
  50.  
  51. #define SICN_HEIGHT         16
  52. #define SICN_ROWS         2
  53. #define CASCADE_ICON_WIDTH    7
  54. #define    SHIFT_ICON_WIDTH    10
  55. #define    OPTION_ICON_WIDTH    16
  56. #define CONTROL_ICON_WIDTH    12
  57. #define COMMAND_ICON_WIDTH    10
  58.  
  59. #define CASCADE_ARROW        0
  60. #define SHIFT_ICON        1
  61. #define OPTION_ICON        2
  62. #define CONTROL_ICON        3
  63. #define COMMAND_ICON        4
  64. #define DOWN_ARROW        5
  65. #define UP_ARROW        6
  66.  
  67. /*
  68.  * Platform specific flags for menu entries
  69.  *
  70.  * ENTRY_COMMAND_ACCEL        Indicates the entry has the command key
  71.  *                in its accelerator string.
  72.  * ENTRY_OPTION_ACCEL        Indicates the entry has the option key
  73.  *                in its accelerator string.
  74.  * ENTRY_SHIFT_ACCEL        Indicates the entry has the shift key
  75.  *                in its accelerator string.
  76.  * ENTRY_CONTROL_ACCEL        Indicates the entry has the control key
  77.  *                in its accelerator string.
  78.  */
  79.  
  80. #define ENTRY_COMMAND_ACCEL    ENTRY_PLATFORM_FLAG1
  81. #define ENTRY_OPTION_ACCEL    ENTRY_PLATFORM_FLAG2
  82. #define ENTRY_SHIFT_ACCEL    ENTRY_PLATFORM_FLAG3
  83. #define ENTRY_CONTROL_ACCEL    ENTRY_PLATFORM_FLAG4
  84. #define ENTRY_ACCEL_MASK    (ENTRY_COMMAND_ACCEL | ENTRY_OPTION_ACCEL \
  85.                 | ENTRY_SHIFT_ACCEL | ENTRY_CONTROL_ACCEL)
  86.  
  87. /*
  88.  * This structure is used to keep track of subfields within Macintosh menu
  89.  * items.
  90.  */
  91.  
  92. typedef struct EntryGeometry {
  93.     int accelTextStart;        /* Offset into the accel string where
  94.                      * the text starts. Everything before
  95.                      * this is modifier key descriptions.
  96.                      */
  97.     int modifierWidth;        /* Width of modifier symbols. */
  98.     int accelTextWidth;        /* Width of the text after the modifier 
  99.                      * keys. */
  100.     int nonAccelMargin;        /* The width of the margin for entries
  101.                      * without accelerators. */
  102. } EntryGeometry;
  103.  
  104. /*
  105.  * Structure to keep track of toplevel windows and their menubars.
  106.  */
  107.  
  108. typedef struct TopLevelMenubarList {
  109.     struct TopLevelMenubarList *nextPtr;
  110.                     /* The next window in the list. */
  111.     Tk_Window tkwin;        /* The toplevel window. */
  112.     TkMenu *menuPtr;        /* The menu associated with this
  113.                      * toplevel. */
  114. } TopLevelMenubarList;
  115.  
  116. /*
  117.  * Platform-specific flags for menus.
  118.  *
  119.  * MENU_APPLE_MENU        0 indicates a custom Apple menu has
  120.  *                not been installed; 1 a custom Apple
  121.  *                menu has been installed.
  122.  * MENU_HELP_MENU        0 indicates a custom Help menu has
  123.  *                not been installed; 1 a custom Help
  124.  *                menu has been installed.
  125.  * MENU_RECONFIGURE_PENDING    1 indicates that an idle handler has
  126.  *                been scheduled to reconfigure the
  127.  *                Macintosh MenuHandle.
  128.  */
  129.  
  130. #define MENU_APPLE_MENU            MENU_PLATFORM_FLAG1
  131. #define MENU_HELP_MENU            MENU_PLATFORM_FLAG2
  132. #define MENU_RECONFIGURE_PENDING    MENU_PLATFORM_FLAG3
  133.  
  134. #define CASCADE_CMD (0x1b)        
  135.                 /* The special command char for cascade
  136.                      * menus. */
  137. #define SEPARATOR_TEXT "\p(-"
  138.                 /* The text for a menu separator. */
  139.  
  140. #define MENUBAR_REDRAW_PENDING 1
  141.  
  142. RgnHandle tkMenuCascadeRgn = NULL;
  143.                 /* The region to clip drawing to when the
  144.                  * MDEF is up. */
  145. int tkUseMenuCascadeRgn = 0;    /* If this is 1, clipping code
  146.                  * should intersect tkMenuCascadeRgn
  147.                  * before drawing occurs.
  148.                  * tkMenuCascadeRgn will only
  149.                  * be valid when the value of this
  150.                  * variable is 1. */
  151.  
  152. static Tcl_HashTable commandTable;
  153.                 /* The list of menuInstancePtrs associated with
  154.                  * menu ids */
  155. static short currentAppleMenuID;
  156.                 /* The id of the current Apple menu. 0 for
  157.                  * none. */
  158. static short currentHelpMenuID; /* The id of the current Help menu. 0 for
  159.                  * none. */
  160. static Tcl_Interp *currentMenuBarInterp;
  161.                 /* The interpreter of the window that owns
  162.                  * the current menubar. */
  163. static char *currentMenuBarName;
  164.                 /* Malloced. Name of current menu in menu bar.
  165.                  * NULL if no menu set. TO DO: make this a
  166.                  * DString. */
  167. static Tk_Window currentMenuBarOwner;
  168.                 /* Which window owns the current menu bar. */
  169. static int helpItemCount;    /* The number of items in the help menu. 
  170.                  * -1 means that the help menu is
  171.                  * unavailable. This does not include
  172.                  * the automatically generated separator. */
  173. static int inPostMenu;        /* We cannot be re-entrant like X
  174.                  * windows. */
  175. static short lastMenuID;    /* To pass to NewMenu; need to figure out
  176.                  * a good way to do this. */
  177. static unsigned char lastCascadeID;
  178.                 /* Cascades have to have ids that are
  179.                  * less than 256. */
  180. static MacDrawable macMDEFDrawable;
  181.                 /* Drawable for use by MDEF code */
  182. static MDEFScrollFlag = 0;    /* Used so that popups don't scroll too soon. */
  183. static int menuBarFlags;    /* Used for whether the menu bar needs
  184.                  * redrawing or not. */
  185. static TkMenuDefUPP menuDefProc;/* The routine descriptor to the MDEF proc.
  186.                  * The MDEF is needed to draw menus with
  187.                  * non-standard attributes and to support
  188.                  * tearoff menus. */
  189. static struct TearoffSelect {
  190.     TkMenu *menuPtr;        /* The menu that is torn off */
  191.     Point point;        /* The point to place the new menu */
  192.     Rect excludeRect;        /* We don't want to drag tearoff highlights
  193.                      * when we are in this menu */
  194. } tearoffStruct;
  195.  
  196. static RgnHandle totalMenuRgn = NULL;
  197.                 /* Used to update windows which have been
  198.                  * obscured by menus. */
  199. static RgnHandle utilRgn = NULL;/* Used when creating the region that is to
  200.                  * be clipped out while the MDEF is active. */
  201.  
  202. static TopLevelMenubarList *windowListPtr;
  203.                 /* A list of windows that have menubars set. */
  204.                 
  205. /*
  206.  * Forward declarations for procedures defined later in this file:
  207.  */
  208.  
  209. static void        CompleteIdlers _ANSI_ARGS_((TkMenu *menuPtr));
  210. static void        DrawMenuBarWhenIdle _ANSI_ARGS_((
  211.                 ClientData clientData));
  212. static void        DrawMenuEntryAccelerator _ANSI_ARGS_((
  213.                 TkMenu *menuPtr, TkMenuEntry *mePtr, 
  214.                 Drawable d, GC gc, Tk_Font tkfont,
  215.                 CONST Tk_FontMetrics *fmPtr,
  216.                 Tk_3DBorder activeBorder, int x, int y,
  217.                 int width, int height, int drawArrow));
  218. static void        DrawMenuEntryBackground _ANSI_ARGS_((
  219.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  220.                 Drawable d, Tk_3DBorder activeBorder,
  221.                 Tk_3DBorder bgBorder, int x, int y,
  222.                 int width, int heigth));
  223. static void        DrawMenuEntryIndicator _ANSI_ARGS_((
  224.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  225.                 Drawable d, GC gc, GC indicatorGC, 
  226.                 Tk_Font tkfont,
  227.                 CONST Tk_FontMetrics *fmPtr, int x, int y,
  228.                 int width, int height));
  229. static void        DrawMenuEntryLabel _ANSI_ARGS_((
  230.                 TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d,
  231.                 GC gc, Tk_Font tkfont,
  232.                 CONST Tk_FontMetrics *fmPtr, int x, int y,
  233.                 int width, int height));
  234. static void        DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr,
  235.                 TkMenuEntry *mePtr, Drawable d, GC gc, 
  236.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  237.                 int x, int y, int width, int height));
  238. static void        DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr,
  239.                 TkMenuEntry *mePtr, Drawable d, GC gc, 
  240.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  241.                 int x, int y, int width, int height));
  242. static void        GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr,
  243.                 TkMenuEntry *mePtr, Tk_Font tkfont,
  244.                 CONST Tk_FontMetrics *fmPtr, int *modWidthPtr,
  245.                 int *textWidthPtr, int *heightPtr));
  246. static void        GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr,
  247.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  248.                 int *widthPtr, int *heightPtr));
  249. static void        GetMenuIndicatorGeometry _ANSI_ARGS_((
  250.                 TkMenu *menuPtr, TkMenuEntry *mePtr, 
  251.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  252.                 int *widthPtr, int *heightPtr));
  253. static void        GetMenuSeparatorGeometry _ANSI_ARGS_((
  254.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  255.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  256.                 int *widthPtr, int *heightPtr));
  257. static void        GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr,
  258.                 TkMenuEntry *mePtr, Tk_Font tkfont,
  259.                 CONST Tk_FontMetrics *fmPtr, int *widthPtr,
  260.                 int *heightPtr));
  261. static int        GetNewID _ANSI_ARGS_((Tcl_Interp *interp,
  262.                 TkMenu *menuInstPtr, int cascade, 
  263.                 short *menuIDPtr));
  264. static char        FindMarkCharacter _ANSI_ARGS_((TkMenuEntry *mePtr));
  265. static void        FreeID _ANSI_ARGS_((short menuID));
  266. static void        InvalidateMDEFRgns _ANSI_ARGS_((void));
  267. static void        MenuDefProc _ANSI_ARGS_((short message,
  268.                 MenuHandle menu, Rect *menuRectPtr,
  269.                 Point hitPt, short *whichItem,
  270.                 TkMenuLowMemGlobals *globalsPtr));
  271. static void        MenuSelectEvent _ANSI_ARGS_((TkMenu *menuPtr));
  272. static void        ReconfigureIndividualMenu _ANSI_ARGS_((
  273.                     TkMenu *menuPtr, MenuHandle macMenuHdl, 
  274.                     int base));
  275. static void        ReconfigureMacintoshMenu _ANSI_ARGS_ ((
  276.                 ClientData clientData));
  277. static void        RecursivelyClearActiveMenu _ANSI_ARGS_((
  278.                 TkMenu *menuPtr));
  279. static void        RecursivelyDeleteMenu _ANSI_ARGS_((
  280.                 TkMenu *menuPtr));
  281. static void        RecursivelyInsertMenu _ANSI_ARGS_((
  282.                 TkMenu *menuPtr));
  283. static void        SetDefaultMenubar _ANSI_ARGS_((void));
  284. static int        SetMenuCascade _ANSI_ARGS_((TkMenu *menuPtr));
  285. static void        SetMenuIndicator _ANSI_ARGS_((TkMenuEntry *mePtr));
  286.  
  287.  
  288. /*
  289.  *----------------------------------------------------------------------
  290.  *
  291.  * TkMacUseID --
  292.  *
  293.  *    Take the ID out of the available list for new menus. Used by the
  294.  *    default menu bar's menus so that they do not get created at the tk
  295.  *    level. See GetNewID for more information.
  296.  *
  297.  * Results:
  298.  *    Returns TCL_OK if the id was not in use. Returns TCL_ERROR if the
  299.  *    id was in use.
  300.  *
  301.  * Side effects:
  302.  *    A hash table entry in the command table is created with a NULL
  303.  *    value.
  304.  *
  305.  *----------------------------------------------------------------------
  306.  */
  307.  
  308. int
  309. TkMacUseMenuID(
  310.     short macID)            /* The id to take out of the table */
  311. {
  312.     Tcl_HashEntry *commandEntryPtr;
  313.     int newEntry;
  314.     
  315.     TkMenuInit();
  316.     commandEntryPtr = Tcl_CreateHashEntry(&commandTable, (char *) macID,
  317.             &newEntry);
  318.     if (newEntry == 1) {
  319.         Tcl_SetHashValue(commandEntryPtr, NULL);
  320.         return TCL_OK;
  321.     } else {
  322.         return TCL_ERROR;
  323.     }
  324. }
  325.  
  326. /*
  327.  *----------------------------------------------------------------------
  328.  *
  329.  * GetNewID --
  330.  *
  331.  *    Allocates a new menu id and marks it in use. Each menu on the
  332.  *    mac must be designated by a unique id, which is a short. In
  333.  *    addition, some ids are reserved by the system. Since Tk uses
  334.  *    mostly dynamic menus, we must allocate and free these ids on
  335.  *    the fly. We use the id as a key into a hash table; if there
  336.  *    is no hash entry, we know that we can use the id.
  337.  *
  338.  * Results:
  339.  *    Returns TCL_OK if succesful; TCL_ERROR if there are no more
  340.  *    ids of the appropriate type to allocate. menuIDPtr contains
  341.  *    the new id if succesful.
  342.  *
  343.  * Side effects:
  344.  *    An entry is created for the menu in the command hash table,
  345.  *    and the hash entry is stored in the appropriate field in the
  346.  *    menu data structure.
  347.  *
  348.  *----------------------------------------------------------------------
  349.  */
  350.  
  351. static int
  352. GetNewID(
  353.     Tcl_Interp *interp,        /* Used for error reporting */
  354.     TkMenu *menuPtr,        /* The menu we are working with */
  355.     int cascade,        /* 0 if we are working with a normal menu;
  356.                        1 if we are working with a cascade */
  357.     short *menuIDPtr)        /* The resulting id */
  358. {
  359.     int found = 0;
  360.     int newEntry;
  361.     Tcl_HashEntry *commandEntryPtr;
  362.     short returnID = *menuIDPtr;
  363.  
  364.     /*
  365.      * The following code relies on shorts and unsigned chars wrapping
  366.      * when the highest value is incremented. Also, the values between
  367.      * 236 and 255 inclusive are reserved for DA's by the Mac OS.
  368.      */
  369.     
  370.     if (!cascade) {
  371.         short curID = lastMenuID + 1;
  372.         if (curID == 236) {
  373.             curID = 256;
  374.         }
  375.  
  376.         while (curID != lastMenuID) {
  377.             commandEntryPtr = Tcl_CreateHashEntry(&commandTable,
  378.             (char *) curID, &newEntry);
  379.             if (newEntry == 1) {
  380.                 found = 1;
  381.                 lastMenuID = returnID = curID;
  382.                 break;
  383.             }
  384.             curID++;
  385.             if (curID == 236) {
  386.                 curID = 256;
  387.             }
  388.         }
  389.     } else {
  390.     
  391.         /*
  392.          * Cascade ids must be between 0 and 235 only, so they must be
  393.          * dealt with separately.
  394.          */
  395.     
  396.         unsigned char curID = lastCascadeID + 1;
  397.         if (curID == 236) {
  398.             curID = 0;
  399.         }
  400.         
  401.         while (curID != lastCascadeID) {
  402.             commandEntryPtr = Tcl_CreateHashEntry(&commandTable,
  403.             (char *) curID, &newEntry);
  404.             if (newEntry == 1) {
  405.                 found = 1;
  406.                 lastCascadeID = returnID = curID;
  407.                 break;
  408.             }
  409.             curID++;
  410.             if (curID == 236) {
  411.                 curID = 0;
  412.             }
  413.         }
  414.     }
  415.  
  416.     if (found) {
  417.         Tcl_SetHashValue(commandEntryPtr, (char *) menuPtr);
  418.         *menuIDPtr = returnID;
  419.         return TCL_OK;
  420.     } else {
  421.         Tcl_AppendResult(interp, "No more menus can be allocated.", 
  422.             (char *) NULL);
  423.         return TCL_ERROR;
  424.     }
  425. }
  426.  
  427. /*
  428.  *----------------------------------------------------------------------
  429.  *
  430.  * FreeID --
  431.  *
  432.  *    Marks the id as free.
  433.  *
  434.  * Results:
  435.  *    None.
  436.  *
  437.  * Side effects:
  438.  *    The hash table entry for the ID is cleared.
  439.  *
  440.  *----------------------------------------------------------------------
  441.  */
  442.  
  443. static void
  444. FreeID(
  445.     short menuID)            /* The id to free */
  446. {
  447.     Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&commandTable,
  448.         (char *) menuID);
  449.     
  450.     if (entryPtr != NULL) {
  451.          Tcl_DeleteHashEntry(entryPtr);
  452.     }
  453.     if (menuID == currentAppleMenuID) {
  454.         currentAppleMenuID = 0;
  455.     }
  456.     if (menuID == currentHelpMenuID) {
  457.         currentHelpMenuID = 0;
  458.     }
  459. }
  460.  
  461. /*
  462.  *----------------------------------------------------------------------
  463.  *
  464.  * TkpNewMenu --
  465.  *
  466.  *    Gets a new blank menu. Only the platform specific options are filled
  467.  *    in.
  468.  *
  469.  * Results:
  470.  *    Returns a standard TCL error.
  471.  *
  472.  * Side effects:
  473.  *    Allocates a Macintosh menu handle and puts in the platformData
  474.  *    field of the menuPtr.
  475.  *
  476.  *----------------------------------------------------------------------
  477.  */
  478.  
  479. int
  480. TkpNewMenu(
  481.     TkMenu *menuPtr)        /* The common structure we are making the
  482.                      * platform structure for. */
  483. {
  484.     short menuID;
  485.     Str255 itemText;
  486.     int length;
  487.     MenuHandle macMenuHdl;
  488.     int error = TCL_OK;
  489.     
  490.     error = GetNewID(menuPtr->interp, menuPtr, 0, &menuID);
  491.     if (error != TCL_OK) {
  492.         return error;
  493.     }
  494.     length = strlen(Tk_PathName(menuPtr->tkwin));
  495.     memmove(&itemText[1], Tk_PathName(menuPtr->tkwin), 
  496.             (length > 230) ? 230 : length);
  497.     itemText[0] = (length > 230) ? 230 : length;
  498.     macMenuHdl = NewMenu(menuID, itemText);
  499. #ifdef GENERATINGCFM
  500.     {
  501.         Handle mdefProc = GetResource('MDEF', 591);
  502.         Handle sicnHandle = GetResource('SICN', SICN_RESOURCE_NUMBER);
  503.     if ((mdefProc != NULL) && (sicnHandle != NULL)) {
  504.             (*macMenuHdl)->menuProc = mdefProc;
  505.         }
  506.     }
  507. #endif
  508.     menuPtr->platformData = (TkMenuPlatformData) ckalloc(sizeof(MacMenu));
  509.     ((MacMenu *) menuPtr->platformData)->menuHdl = macMenuHdl;
  510.     SetRect(&((MacMenu *) menuPtr->platformData)->menuRect, 0, 0, 0, 0);
  511.  
  512.     if ((currentMenuBarInterp == menuPtr->interp)
  513.             && (currentMenuBarName != NULL)) {
  514.         Tk_Window parentWin = Tk_Parent(menuPtr->tkwin);
  515.         
  516.         if (strcmp(currentMenuBarName, Tk_PathName(parentWin)) == 0) {
  517.             if ((strcmp(Tk_PathName(menuPtr->tkwin)
  518.                     + strlen(Tk_PathName(parentWin)), ".apple") == 0)
  519.                     || (strcmp(Tk_PathName(menuPtr->tkwin)
  520.                     + strlen(Tk_PathName(parentWin)), ".help") == 0)) {
  521.             if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
  522.                 Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL);
  523.                 menuBarFlags |= MENUBAR_REDRAW_PENDING;
  524.             }
  525.         }                   
  526.         }
  527.     }
  528.     
  529.     menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  530.     Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
  531.     return TCL_OK;
  532. }
  533.  
  534. /*
  535.  *----------------------------------------------------------------------
  536.  *
  537.  * TkpDestroyMenu --
  538.  *
  539.  *    Destroys platform-specific menu structures.
  540.  *
  541.  * Results:
  542.  *    None.
  543.  *
  544.  * Side effects:
  545.  *    All platform-specific allocations are freed up.
  546.  *
  547.  *----------------------------------------------------------------------
  548.  */
  549.  
  550. void
  551. TkpDestroyMenu(
  552.     TkMenu *menuPtr)        /* The common menu structure */
  553. {
  554.     MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
  555.  
  556.     if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
  557.         Tcl_CancelIdleCall(ReconfigureMacintoshMenu, (ClientData) menuPtr);
  558.         menuPtr->menuFlags &= ~MENU_RECONFIGURE_PENDING;
  559.     }
  560.  
  561.     if ((*macMenuHdl)->menuID == currentHelpMenuID) {
  562.         MenuHandle helpMenuHdl;
  563.         
  564.         if ((HMGetHelpMenuHandle(&helpMenuHdl) == noErr) 
  565.             && (helpMenuHdl != NULL)) {
  566.             int i, count = CountMItems(helpMenuHdl);
  567.             
  568.             for (i = helpItemCount; i <= count; i++) {
  569.                 DeleteMenuItem(helpMenuHdl, helpItemCount);
  570.             }
  571.         }
  572.         currentHelpMenuID = 0;
  573.     }
  574.  
  575.     if (menuPtr->platformData != NULL) {
  576.     DeleteMenu((*macMenuHdl)->menuID);
  577.     FreeID((*macMenuHdl)->menuID);
  578.     DisposeMenu(macMenuHdl);
  579.     ckfree((char *) menuPtr->platformData);
  580.     menuPtr->platformData = NULL;
  581.     }
  582. }
  583.  
  584. /*
  585.  *----------------------------------------------------------------------
  586.  *
  587.  * SetMenuCascade --
  588.  *
  589.  *    Does any cleanup to change a menu from a normal to a cascade.
  590.  *
  591.  * Results:
  592.  *    Standard Tcl error.
  593.  *
  594.  * Side effects:
  595.  *    The mac menu id is reset.
  596.  *
  597.  *----------------------------------------------------------------------
  598.  */
  599.  
  600. static int
  601. SetMenuCascade(
  602.     TkMenu* menuPtr)        /* The menu we are setting up to be a
  603.                  * cascade. */
  604. {
  605.     MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
  606.     short newMenuID, menuID = (*macMenuHdl)->menuID;
  607.     int error = TCL_OK;
  608.     
  609.     if (menuID >= 256) {
  610.         error = GetNewID(menuPtr->interp, menuPtr, 1, &newMenuID);
  611.         if (error == TCL_OK) {
  612.             FreeID(menuID);
  613.             (*macMenuHdl)->menuID = newMenuID;
  614.         }
  615.     }
  616.     return error;
  617. }
  618.  
  619. /*
  620.  *----------------------------------------------------------------------
  621.  *
  622.  * TkpDestroyMenuEntry --
  623.  *
  624.  *    Cleans up platform-specific menu entry items.
  625.  *
  626.  * Results:
  627.  *    None
  628.  *
  629.  * Side effects:
  630.  *    All platform-specific allocations are freed up.
  631.  *
  632.  *----------------------------------------------------------------------
  633.  */
  634.  
  635. void
  636. TkpDestroyMenuEntry(
  637.     TkMenuEntry *mePtr)        /* The common structure for the menu 
  638.                      * entry. */
  639. {
  640.     TkMenu *menuPtr = mePtr->menuPtr;    
  641.   
  642.     ckfree((char *) mePtr->platformEntryData);
  643.     if ((menuPtr->platformData != NULL) 
  644.             && !(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
  645.         menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  646.         Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
  647.     }
  648. }
  649.  
  650. /*
  651.  *----------------------------------------------------------------------
  652.  *
  653.  * GetEntryText --
  654.  *
  655.  *    Given a menu entry, gives back the text that should go in it.
  656.  *    Separators should be done by the caller, as they have to be
  657.  *    handled specially.
  658.  *
  659.  * Results:
  660.  *    itemText points to the new text for the item.
  661.  *
  662.  * Side effects:
  663.  *    None.
  664.  *
  665.  *----------------------------------------------------------------------
  666.  */
  667.  
  668. static void
  669. GetEntryText(
  670.     TkMenuEntry *mePtr,        /* A pointer to the menu entry. */
  671.     Str255 itemText)        /* The pascal string containing the text */
  672. {
  673.     if (mePtr->type == TEAROFF_ENTRY) {
  674.     strcpy((char *)itemText, (const char *)"\p(Tear-off)");
  675.     } else if (mePtr->imageString != NULL) {
  676.     strcpy((char *)itemText, (const char *)"\p(Image)");
  677.     } else if (mePtr->bitmap != None) {
  678.     strcpy((char *)itemText, (const char *)"\p(Pixmap)");
  679.     } else if (mePtr->label == NULL || mePtr->labelLength == 0) {
  680.     
  681.     /*
  682.      * The Mac menu manager does not like null strings.
  683.      */
  684.      
  685.     strcpy((char *)itemText, (const char *)"\p ");
  686.     } else {
  687.         char *text = mePtr->label;
  688.         int i;
  689.         
  690.         itemText[0] = 0;
  691.         for (i = 1; (*text != '\0') && (i <= 230); i++, text++) {
  692.             if ((*text == '.')
  693.                     && (*(text + 1) != '\0') && (*(text + 1) == '.')
  694.                     && (*(text + 2) != '\0') && (*(text + 2) == '.')) {
  695.                 itemText[i] = '…';
  696.                 text += 2;
  697.             } else {
  698.                 itemText[i] = *text;
  699.             }
  700.             itemText[0] += 1;
  701.         }
  702.     }
  703. }
  704.  
  705. /*
  706.  *----------------------------------------------------------------------
  707.  *
  708.  * FindMarkCharacter --
  709.  *
  710.  *    Finds the Macintosh mark character based on the font of the
  711.  *    item. We calculate a good mark character based on the font
  712.  *     that this item is rendered in.
  713.  *
  714.  *     We try the following special mac characters. If none of them
  715.  *     are present, just use the check mark.
  716.  *     '' - Check mark character
  717.  *     '•' - Bullet character
  718.  *     '' - Filled diamond
  719.  *     'â—Š' - Hollow diamond
  720.  *     '—' = Long dash ("em dash")
  721.  *     '-' = short dash (minus, "en dash");
  722.  *
  723.  * Results:
  724.  *    None.
  725.  *
  726.  * Side effects:
  727.  *    New item is added to platform menu
  728.  *
  729.  *----------------------------------------------------------------------
  730.  */
  731.  
  732. static char
  733. FindMarkCharacter(
  734.     TkMenuEntry *mePtr)        /* The entry we are finding the character
  735.                      * for. */
  736. {
  737.     char markChar;
  738.     Tk_Font tkfont = (mePtr->tkfont == NULL) ? mePtr->menuPtr->tkfont
  739.             : mePtr->tkfont;
  740.             
  741.     if (!TkMacIsCharacterMissing(tkfont, '')) {
  742.         markChar = '';
  743.     } else if (!TkMacIsCharacterMissing(tkfont, '•')) {
  744.         markChar = '•';
  745.     } else if (!TkMacIsCharacterMissing(tkfont, '')) {
  746.         markChar = '';
  747.     } else if (!TkMacIsCharacterMissing(tkfont, 'â—Š')) {
  748.         markChar = 'â—Š';
  749.     } else if (!TkMacIsCharacterMissing(tkfont, '—')) {
  750.         markChar = '—';
  751.     } else if (!TkMacIsCharacterMissing(tkfont, '-')) {
  752.         markChar = '-';
  753.     } else {
  754.         markChar = '';
  755.     }
  756.     return markChar;
  757. }
  758.  
  759. /*
  760.  *----------------------------------------------------------------------
  761.  *
  762.  * SetMenuIndicator --
  763.  *
  764.  *    Sets the Macintosh mark character based on the font of the
  765.  *    item.
  766.  *
  767.  * Results:
  768.  *    None.
  769.  *
  770.  * Side effects:
  771.  *    New item is added to platform menu
  772.  *
  773.  *----------------------------------------------------------------------
  774.  */
  775.  
  776. static void
  777. SetMenuIndicator(
  778.     TkMenuEntry *mePtr)        /* The entry we are setting */
  779. {
  780.     TkMenu *menuPtr = mePtr->menuPtr;
  781.     MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
  782.     char markChar;
  783.  
  784.     /*
  785.      * There can be no indicators on menus that are not checkbuttons
  786.      * or radiobuttons. However, we should go ahead and set them
  787.      * so that menus look right when they are displayed. We should
  788.      * not set cascade entries, however, as the mark character
  789.      * means something different for cascade items on the Mac.
  790.      * Also, we do reflect the tearOff menu items in the Mac menu
  791.      * handle, so we ignore them.
  792.      */
  793.  
  794.     if (mePtr->type == CASCADE_ENTRY) {
  795.         return;
  796.     }
  797.      
  798.     if (((mePtr->type == RADIO_BUTTON_ENTRY) 
  799.             || (mePtr->type == CHECK_BUTTON_ENTRY))
  800.             && (mePtr->indicatorOn)
  801.             && (mePtr->entryFlags & ENTRY_SELECTED)) {
  802.         markChar = FindMarkCharacter(mePtr);
  803.     } else {
  804.         markChar = 0;
  805.     }
  806.     SetItemMark(macMenuHdl, mePtr->index + 1, markChar);
  807. }
  808.  
  809. /*
  810.  *----------------------------------------------------------------------
  811.  *
  812.  * SetMenuTitle --
  813.  *
  814.  *    Sets title of menu so that the text displays correctly in menubar.
  815.  *    This code directly manipulates menu handle data. This code
  816.  *    was originally part of an ancient Apple Developer Response mail.
  817.  *
  818.  * Results:
  819.  *    None.
  820.  *
  821.  * Side effects:
  822.  *    The menu handle will change size depending on the length of the
  823.  *    title
  824.  *
  825.  *----------------------------------------------------------------------
  826.  */
  827.  
  828. static void
  829. SetMenuTitle(
  830.     MenuHandle menuHdl,        /* The menu we are setting the title of. */
  831.     char *title)        /* The C string to set the title to. */
  832. {
  833.     int oldLength, newLength, oldHandleSize, dataLength;
  834.     Ptr menuDataPtr;
  835.  
  836.     menuDataPtr = (Ptr) (*menuHdl)->menuData;
  837.  
  838.     if (strncmp(title, menuDataPtr + 1, menuDataPtr[0]) != 0) {    
  839.         newLength = strlen(title) + 1;
  840.         oldLength = menuDataPtr[0] + 1;
  841.         oldHandleSize = GetHandleSize((Handle) menuHdl);
  842.         dataLength = oldHandleSize - (sizeof(MenuInfo) - sizeof(Str255)) 
  843.             - oldLength;
  844.         if (newLength > oldLength) {
  845.             SetHandleSize((Handle) menuHdl, oldHandleSize + (newLength 
  846.                     - oldLength));
  847.             menuDataPtr = (Ptr) (*menuHdl)->menuData;
  848.         }
  849.     
  850.         BlockMove(menuDataPtr + oldLength, menuDataPtr + newLength, 
  851.             dataLength);
  852.         BlockMove(title, menuDataPtr + 1, newLength - 1);
  853.         menuDataPtr[0] = newLength - 1;
  854.     
  855.         if (newLength < oldLength) {
  856.             SetHandleSize((Handle) menuHdl, oldHandleSize + (newLength 
  857.                     - oldLength));
  858.         }
  859.     }
  860. }
  861.  
  862. /*
  863.  *----------------------------------------------------------------------
  864.  *
  865.  * TkpConfigureMenuEntry --
  866.  *
  867.  *    Processes configurations for menu entries.
  868.  *
  869.  * Results:
  870.  *    Returns standard TCL result. If TCL_ERROR is returned, then
  871.  *    interp->result contains an error message.
  872.  *
  873.  * Side effects:
  874.  *    Configuration information get set for mePtr; old resources
  875.  *    get freed, if any need it.
  876.  *
  877.  *----------------------------------------------------------------------
  878.  */
  879.  
  880. int
  881. TkpConfigureMenuEntry(
  882.     register TkMenuEntry *mePtr)    /* Information about menu entry;  may
  883.                      * or may not already have values for
  884.                      * some fields. */
  885. {
  886.     TkMenu *menuPtr = mePtr->menuPtr;
  887.     int index = mePtr->index;
  888.     MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
  889.     MenuHandle helpMenuHdl = NULL;
  890.  
  891.     /*
  892.      * Cascade menus have to have menu IDs of less than 256. So
  893.      * we need to change the child menu if this has been configured
  894.      * for a cascade item.
  895.      */
  896.     
  897.     if (mePtr->type == CASCADE_ENTRY) {
  898.         if ((mePtr->childMenuRefPtr != NULL)
  899.             && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
  900.             MenuHandle childMenuHdl = ((MacMenu *) mePtr
  901.                     ->childMenuRefPtr->menuPtr->platformData)->menuHdl;
  902.             
  903.             if (childMenuHdl != NULL) {
  904.                 int error = SetMenuCascade(mePtr->childMenuRefPtr->menuPtr);
  905.                 
  906.                 if (error != TCL_OK) {
  907.                     return error;
  908.                 }
  909.                 
  910.                 if (menuPtr->menuType == MENUBAR) {
  911.                     SetMenuTitle(childMenuHdl, mePtr->label);
  912.                 }
  913.             }
  914.         }
  915.     }
  916.     
  917.     /*
  918.      * We need to parse the accelerator string. If it has the strings
  919.      * for Command, Control, Shift or Option, we need to flag it
  920.      * so we can draw the symbols for it. We also need to precalcuate
  921.      * the position of the first real character we are drawing.
  922.      */
  923.     
  924.     if (0 == mePtr->accelLength) {
  925.         ((EntryGeometry *)mePtr->platformEntryData)->accelTextStart = -1;
  926.     } else {
  927.     char *accelString = mePtr->accel;
  928.     mePtr->entryFlags |= ~ENTRY_ACCEL_MASK;
  929.         
  930.     while (1) {
  931.         if ((0 == strncasecmp("Control", accelString, 6))
  932.                 && (('-' == accelString[6]) || ('+' == accelString[6]))) {
  933.           mePtr->entryFlags |= ENTRY_CONTROL_ACCEL;
  934.           accelString += 7;
  935.         } else if ((0 == strncasecmp("Ctrl", accelString, 4))
  936.                 && (('-' == accelString[4]) || ('+' == accelString[4]))) {
  937.           mePtr->entryFlags |= ENTRY_CONTROL_ACCEL;
  938.           accelString += 5;
  939.         } else if ((0 == strncasecmp("Shift", accelString, 5))
  940.                 && (('-' == accelString[5]) || ('+' == accelString[5]))) {
  941.           mePtr->entryFlags |= ENTRY_SHIFT_ACCEL;
  942.           accelString += 6;
  943.         } else if ((0 == strncasecmp("Option", accelString, 6))
  944.                 && (('-' == accelString[6]) || ('+' == accelString[6]))) {
  945.           mePtr->entryFlags |= ENTRY_OPTION_ACCEL;
  946.           accelString += 7;
  947.         } else if ((0 == strncasecmp("Opt", accelString, 3))
  948.                 && (('-' == accelString[3]) || ('+' == accelString[3]))) {
  949.           mePtr->entryFlags |= ENTRY_OPTION_ACCEL;
  950.           accelString += 4;
  951.         } else if ((0 == strncasecmp("Command", accelString, 7))
  952.                 && (('-' == accelString[7]) || ('+' == accelString[7]))) {
  953.           mePtr->entryFlags |= ENTRY_COMMAND_ACCEL;
  954.           accelString += 8;
  955.         } else if ((0 == strncasecmp("Cmd", accelString, 3))
  956.                 && (('-' == accelString[3]) || ('+' == accelString[3]))) {
  957.           mePtr->entryFlags |= ENTRY_COMMAND_ACCEL;
  958.           accelString += 4;
  959.         } else if ((0 == strncasecmp("Alt", accelString, 3))
  960.                 && (('-' == accelString[3]) || ('+' == accelString[3]))) {
  961.           mePtr->entryFlags |= ENTRY_OPTION_ACCEL;
  962.           accelString += 4;
  963.         } else if ((0 == strncasecmp("Meta", accelString, 4))
  964.                 && (('-' == accelString[4]) || ('+' == accelString[4]))) {
  965.           mePtr->entryFlags |= ENTRY_COMMAND_ACCEL;
  966.           accelString += 5;
  967.         } else {
  968.           break;
  969.         }
  970.     }
  971.         
  972.     ((EntryGeometry *)mePtr->platformEntryData)->accelTextStart 
  973.         = ((long) accelString - (long) mePtr->accel);
  974.     }
  975.     
  976.     if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
  977.         menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  978.         Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
  979.     }
  980.     
  981.     return TCL_OK;
  982. }
  983.  
  984. /*
  985.  *----------------------------------------------------------------------
  986.  *
  987.  * ReconfigureIndividualMenu --
  988.  *
  989.  *    This routine redoes the guts of the menu. It works from
  990.  *    a base item and offset, so that a regular menu will
  991.  *    just have all of its items added, but the help menu will
  992.  *    have all of its items appended after the apple-defined
  993.  *    items.
  994.  *
  995.  * Results:
  996.  *    None.
  997.  *
  998.  * Side effects:
  999.  *    The Macintosh menu handle is updated
  1000.  *
  1001.  *----------------------------------------------------------------------
  1002.  */
  1003.  
  1004. static void
  1005. ReconfigureIndividualMenu(
  1006.     TkMenu *menuPtr,        /* The menu we are affecting. */
  1007.     MenuHandle macMenuHdl,    /* The macintosh menu we are affecting.
  1008.                      * Will not necessarily be
  1009.                      * menuPtr->platformData because this could
  1010.                      * be the help menu. */
  1011.     int base)            /* The last index that we do not want
  1012.                      * touched. 0 for normal menus;
  1013.                      * helpMenuItemCount for help menus. */
  1014. {
  1015.     int count;
  1016.     int index;
  1017.     TkMenuEntry *mePtr;
  1018.     Str255 itemText;
  1019.     int parentDisabled = 0;
  1020.     
  1021.     for (mePtr = menuPtr->menuRefPtr->parentEntryPtr; mePtr != NULL;
  1022.             mePtr = mePtr->nextCascadePtr) {
  1023.         if (strcmp(Tk_PathName(menuPtr->tkwin), mePtr->name) == 0) {
  1024.             if (mePtr->state == tkDisabledUid) {
  1025.                 parentDisabled = 1;
  1026.             }
  1027.             break;
  1028.         }
  1029.     }
  1030.     
  1031.     /*
  1032.      * First, we get rid of all of the old items.
  1033.      */
  1034.     
  1035.     count = CountMItems(macMenuHdl);
  1036.     for (index = base; index < count; index++) {
  1037.         DeleteMenuItem(macMenuHdl, base + 1);
  1038.     }
  1039.  
  1040.     count = menuPtr->numEntries;
  1041.     
  1042.     for (index = 1; index <= count; index++) {
  1043.         mePtr = menuPtr->entries[index - 1];
  1044.     
  1045.         /*
  1046.          * We have to do separators separately because SetMenuItemText
  1047.          * does not parse meta-characters.
  1048.          */
  1049.     
  1050.         if (mePtr->type == SEPARATOR_ENTRY) {
  1051.             AppendMenu(macMenuHdl, SEPARATOR_TEXT);
  1052.         } else {
  1053.         GetEntryText(mePtr, itemText);
  1054.         AppendMenu(macMenuHdl, "\px");
  1055.         SetMenuItemText(macMenuHdl, base + index, itemText);
  1056.     
  1057.             /*
  1058.              * Set enabling and disabling correctly.
  1059.              */
  1060.  
  1061.         if (parentDisabled || (mePtr->state == tkDisabledUid)) {
  1062.             DisableItem(macMenuHdl, base + index);
  1063.         } else {
  1064.             EnableItem(macMenuHdl, base + index);
  1065.         }
  1066.         
  1067.             /*
  1068.              * Set the check mark for check entries and radio entries.
  1069.              */
  1070.     
  1071.         SetItemMark(macMenuHdl, base + index, 0);        
  1072.         if ((mePtr->type == CHECK_BUTTON_ENTRY)
  1073.             || (mePtr->type == RADIO_BUTTON_ENTRY)) {
  1074.             CheckItem(macMenuHdl, base + index, (mePtr->entryFlags
  1075.                 & ENTRY_SELECTED) && (mePtr->indicatorOn));
  1076.         if ((mePtr->indicatorOn)
  1077.             && (mePtr->entryFlags & ENTRY_SELECTED)) {
  1078.             SetItemMark(macMenuHdl, base + index,
  1079.                     FindMarkCharacter(mePtr));
  1080.             }
  1081.         }
  1082.     
  1083.         if (mePtr->type == CASCADE_ENTRY) {
  1084.             if ((mePtr->childMenuRefPtr != NULL) 
  1085.                     && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
  1086.                 MenuHandle childMenuHdl = 
  1087.                         ((MacMenu *) mePtr->childMenuRefPtr
  1088.                 ->menuPtr->platformData)->menuHdl;
  1089.  
  1090.             if (childMenuHdl == NULL) {
  1091.                 childMenuHdl = ((MacMenu *) mePtr->childMenuRefPtr
  1092.                     ->menuPtr->platformData)->menuHdl;
  1093.             }
  1094.             if (childMenuHdl != NULL) {
  1095.                     SetItemMark(macMenuHdl, base + index,
  1096.                 (*childMenuHdl)->menuID);
  1097.                     SetItemCmd(macMenuHdl, base + index, CASCADE_CMD);
  1098.                 }
  1099.                 /*
  1100.                  * If we changed the highligthing of this menu, its
  1101.                  * children all have to be reconfigured so that
  1102.                  * their state will be reflected in the menubar.
  1103.                  */
  1104.         
  1105.                 if (!(mePtr->childMenuRefPtr->menuPtr->menuFlags 
  1106.                             & MENU_RECONFIGURE_PENDING)) {
  1107.                     mePtr->childMenuRefPtr->menuPtr->menuFlags
  1108.                         |= MENU_RECONFIGURE_PENDING;
  1109.                     Tcl_DoWhenIdle(ReconfigureMacintoshMenu, 
  1110.                         (ClientData) mePtr->childMenuRefPtr->menuPtr);
  1111.                 }
  1112.             }
  1113.         }
  1114.         
  1115.             if ((mePtr->type != CASCADE_ENTRY) 
  1116.                     && (ENTRY_COMMAND_ACCEL 
  1117.                     == (mePtr->entryFlags & ENTRY_ACCEL_MASK))) {
  1118.             SetItemCmd(macMenuHdl, index, mePtr
  1119.             ->accel[((EntryGeometry *)mePtr->platformEntryData)
  1120.                 ->accelTextStart]);
  1121.         }
  1122.         }
  1123.     }
  1124. }
  1125.  
  1126. /*
  1127.  *----------------------------------------------------------------------
  1128.  *
  1129.  * ReconfigureMacintoshMenu --
  1130.  *
  1131.  *    Rebuilds the Macintosh MenuHandle items from the menu. Called
  1132.  *    usually as an idle handler, but can be called synchronously
  1133.  *    if the menu is about to be posted.
  1134.  *
  1135.  * Results:
  1136.  *    None.
  1137.  *
  1138.  * Side effects:
  1139.  *    Configuration information get set for mePtr; old resources
  1140.  *    get freed, if any need it.
  1141.  *
  1142.  *----------------------------------------------------------------------
  1143.  */
  1144.  
  1145. static void
  1146. ReconfigureMacintoshMenu(
  1147.     ClientData clientData)        /* Information about menu entry;  may
  1148.                      * or may not already have values for
  1149.                      * some fields. */
  1150. {
  1151.     TkMenu *menuPtr = (TkMenu *) clientData;
  1152.     MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
  1153.     MenuHandle helpMenuHdl = NULL;
  1154.  
  1155.     menuPtr->menuFlags &= ~MENU_RECONFIGURE_PENDING;
  1156.  
  1157.     if (NULL == macMenuHdl) {
  1158.         return;
  1159.     }
  1160.  
  1161.     ReconfigureIndividualMenu(menuPtr, macMenuHdl, 0);
  1162.  
  1163.     if (menuPtr->menuFlags & MENU_APPLE_MENU) {
  1164.         AddResMenu(macMenuHdl, 'DRVR');
  1165.     }
  1166.  
  1167.     if ((*macMenuHdl)->menuID == currentHelpMenuID) {
  1168.         HMGetHelpMenuHandle(&helpMenuHdl);
  1169.         if (helpMenuHdl != NULL) {
  1170.             ReconfigureIndividualMenu(menuPtr, helpMenuHdl, helpItemCount);
  1171.         }
  1172.     }
  1173.  
  1174.     if (menuPtr->menuType == MENUBAR) {
  1175.         if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
  1176.             Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL);
  1177.             menuBarFlags |= MENUBAR_REDRAW_PENDING;
  1178.         }
  1179.     }
  1180. }
  1181.  
  1182. /*
  1183.  *----------------------------------------------------------------------
  1184.  *
  1185.  * CompleteIdlers --
  1186.  *
  1187.  *    Completes all idle handling so that the menus are in sync when
  1188.  *    the user invokes them with the mouse.
  1189.  *
  1190.  * Results:
  1191.  *    None.
  1192.  *
  1193.  * Side effects:
  1194.  *    The Macintosh menu handles are flushed out.
  1195.  *
  1196.  *----------------------------------------------------------------------
  1197.  */
  1198.  
  1199. static void
  1200. CompleteIdlers(
  1201.     TkMenu *menuPtr)            /* The menu we are completing. */
  1202. {
  1203.     int i;
  1204.  
  1205.     if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
  1206.         Tcl_CancelIdleCall(ReconfigureMacintoshMenu, (ClientData) menuPtr);
  1207.         ReconfigureMacintoshMenu((ClientData) menuPtr);
  1208.     }
  1209.     
  1210.     for (i = 0; i < menuPtr->numEntries; i++) {
  1211.         if (menuPtr->entries[i]->type == CASCADE_ENTRY) {
  1212.             if ((menuPtr->entries[i]->childMenuRefPtr != NULL)
  1213.                     && (menuPtr->entries[i]->childMenuRefPtr->menuPtr
  1214.             != NULL)) {
  1215.         CompleteIdlers(menuPtr->entries[i]->childMenuRefPtr
  1216.             ->menuPtr);
  1217.         }
  1218.         }
  1219.     }
  1220. }
  1221.  
  1222. /*
  1223.  *----------------------------------------------------------------------
  1224.  *
  1225.  * TkpPostMenu --
  1226.  *
  1227.  *    Posts a menu on the screen
  1228.  *
  1229.  * Results:
  1230.  *    None.
  1231.  *
  1232.  * Side effects:
  1233.  *    The menu is posted and handled.
  1234.  *
  1235.  *----------------------------------------------------------------------
  1236.  */
  1237.  
  1238. int
  1239. TkpPostMenu(
  1240.     Tcl_Interp *interp,        /* The interpreter this menu lives in */
  1241.     TkMenu *menuPtr,        /* The menu we are posting */
  1242.     int x,            /* The global x-coordinate of the top, left-
  1243.                      * hand corner of where the menu is supposed
  1244.                      * to be posted. */
  1245.     int y)            /* The global y-coordinate */
  1246. {
  1247.     MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
  1248.     long popUpResult;
  1249.     int result;
  1250.     int oldMode;
  1251.  
  1252.     if (inPostMenu) {
  1253.         Tcl_AppendResult(interp,
  1254.         "Cannot call post menu while already posting menu",
  1255.         (char *) NULL);
  1256.         result = TCL_ERROR;
  1257.     } else {
  1258.         Window dummyWin;
  1259.         unsigned int state;
  1260.         int dummy, mouseX, mouseY;
  1261.         short menuID;
  1262.     Window window;
  1263.     int oldWidth = menuPtr->totalWidth;
  1264.     Tk_Window parentWindow = Tk_Parent(menuPtr->tkwin);
  1265.     
  1266.         inPostMenu++;
  1267.         
  1268.         result = TkPreprocessMenu(menuPtr);
  1269.         if (result != TCL_OK) {
  1270.             inPostMenu--;
  1271.             return result;
  1272.         }
  1273.  
  1274.         /*
  1275.          * The post commands could have deleted the menu, which means
  1276.          * we are dead and should go away.
  1277.          */
  1278.         
  1279.         if (menuPtr->tkwin == NULL) {
  1280.             inPostMenu--;
  1281.             return TCL_OK;
  1282.         }
  1283.  
  1284.         CompleteIdlers(menuPtr);
  1285.         if (menuBarFlags & MENUBAR_REDRAW_PENDING) {
  1286.             Tcl_CancelIdleCall(DrawMenuBarWhenIdle, (ClientData *) NULL);
  1287.             DrawMenuBarWhenIdle((ClientData *) NULL);
  1288.         }
  1289.         
  1290.     if (NULL == parentWindow) {
  1291.         tearoffStruct.excludeRect.top = tearoffStruct.excludeRect.left
  1292.                 = tearoffStruct.excludeRect.bottom
  1293.             = tearoffStruct.excludeRect.right = SHRT_MAX;
  1294.     } else {
  1295.         int left, top;
  1296.     
  1297.         Tk_GetRootCoords(parentWindow, &left, &top);
  1298.         tearoffStruct.excludeRect.left = left;
  1299.         tearoffStruct.excludeRect.top = top;
  1300.         tearoffStruct.excludeRect.right = left + Tk_Width(parentWindow);
  1301.         tearoffStruct.excludeRect.bottom = top + Tk_Height(parentWindow);
  1302.         if (Tk_Class(parentWindow) == Tk_GetUid("Menubutton")) {
  1303.             TkWindow *parentWinPtr = (TkWindow *) parentWindow;
  1304.             TkMenuButton *mbPtr = 
  1305.                 (TkMenuButton *) parentWinPtr->instanceData;
  1306.             int menuButtonWidth = Tk_Width(parentWindow)
  1307.                 - 2 * (mbPtr->highlightWidth + mbPtr->borderWidth + 1);
  1308.             menuPtr->totalWidth = menuButtonWidth > menuPtr->totalWidth
  1309.                 ? menuButtonWidth : menuPtr->totalWidth;
  1310.         }
  1311.     }
  1312.          
  1313.         InsertMenu(macMenuHdl, -1);
  1314.         RecursivelyInsertMenu(menuPtr);
  1315.         CountMItems(macMenuHdl);
  1316.         
  1317.     oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  1318.     popUpResult = PopUpMenuSelect(macMenuHdl, y, x, menuPtr->active);
  1319.     Tcl_SetServiceMode(oldMode);
  1320.  
  1321.     menuPtr->totalWidth = oldWidth;
  1322.     RecursivelyDeleteMenu(menuPtr);
  1323.     DeleteMenu((*macMenuHdl)->menuID);
  1324.     
  1325.     /*
  1326.      * Simulate the mouse up.
  1327.      */
  1328.      
  1329.     XQueryPointer(NULL, None, &dummyWin, &dummyWin, &mouseX,
  1330.         &mouseY, &dummy, &dummy, &state);
  1331.     window = Tk_WindowId(menuPtr->tkwin);
  1332.     TkGenerateButtonEvent(mouseX, mouseY, window, state);
  1333.     
  1334.     /*
  1335.      * Dispatch the command.
  1336.      */
  1337.      
  1338.     menuID = HiWord(popUpResult);
  1339.     if (menuID != 0) {
  1340.         result = TkMacDispatchMenuEvent(menuID, LoWord(popUpResult));
  1341.     } else {
  1342.         TkMacHandleTearoffMenu();
  1343.         result = TCL_OK;
  1344.     }
  1345.     InvalidateMDEFRgns();
  1346.     RecursivelyClearActiveMenu(menuPtr);
  1347.     
  1348.     inPostMenu--;
  1349.     }
  1350.     return result;
  1351. }
  1352.  
  1353. /*
  1354.  *----------------------------------------------------------------------
  1355.  *
  1356.  * TkpMenuNewEntry --
  1357.  *
  1358.  *    Adds a pointer to a new menu entry structure with the platform-
  1359.  *    specific fields filled in. The Macintosh uses the
  1360.  *    platformEntryData field of the TkMenuEntry record to store
  1361.  *    geometry information.
  1362.  *
  1363.  * Results:
  1364.  *    Standard TCL error.
  1365.  *
  1366.  * Side effects:
  1367.  *    Storage gets allocated. New menu entry data is put into the
  1368.  *    platformEntryData field of the mePtr.
  1369.  *
  1370.  *----------------------------------------------------------------------
  1371.  */
  1372.  
  1373. int
  1374. TkpMenuNewEntry(
  1375.     TkMenuEntry *mePtr)        /* The menu we are adding an entry to */
  1376. {
  1377.     EntryGeometry *geometryPtr =
  1378.         (EntryGeometry *) ckalloc(sizeof(EntryGeometry));
  1379.     TkMenu *menuPtr = mePtr->menuPtr;
  1380.     
  1381.     geometryPtr->accelTextStart = 0;
  1382.     geometryPtr->accelTextWidth = 0;
  1383.     geometryPtr->nonAccelMargin = 0;
  1384.     geometryPtr->modifierWidth = 0;
  1385.     mePtr->platformEntryData = (TkMenuPlatformEntryData) geometryPtr;
  1386.     if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
  1387.         menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  1388.         Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
  1389.     }
  1390.     return TCL_OK;
  1391. }
  1392.  
  1393. /*
  1394.  *----------------------------------------------------------------------
  1395.  *
  1396.  * 
  1397.  * DrawMenuBarWhenIdle --
  1398.  *
  1399.  *    Update the menu bar next time there is an idle event.
  1400.  *
  1401.  * Results:
  1402.  *    None.
  1403.  *
  1404.  * Side effects:
  1405.  *    Menu bar is redrawn.
  1406.  *
  1407.  *----------------------------------------------------------------------
  1408.  */
  1409.  
  1410. static void
  1411. DrawMenuBarWhenIdle(
  1412.     ClientData clientData)    /* ignored here */
  1413. {
  1414.     TkMenuReferences *menuRefPtr;
  1415.     TkMenu *appleMenuPtr, *helpMenuPtr;
  1416.     MenuHandle macMenuHdl;
  1417.     Tcl_HashEntry *hashEntryPtr;
  1418.     
  1419.     /*
  1420.      * We need to clear the apple and help menus of any extra items.
  1421.      */
  1422.  
  1423.     if (currentAppleMenuID != 0) {
  1424.         hashEntryPtr = Tcl_FindHashEntry(&commandTable,
  1425.             (char *) currentAppleMenuID);
  1426.         appleMenuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
  1427.         TkpDestroyMenu(appleMenuPtr);
  1428.         TkpNewMenu(appleMenuPtr);
  1429.         appleMenuPtr->menuFlags &= ~MENU_APPLE_MENU;
  1430.         appleMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  1431.         Tcl_DoWhenIdle(ReconfigureMacintoshMenu, 
  1432.             (ClientData) appleMenuPtr);
  1433.     }
  1434.  
  1435.     if (currentHelpMenuID != 0) {
  1436.         hashEntryPtr = Tcl_FindHashEntry(&commandTable,
  1437.             (char *) currentHelpMenuID);
  1438.         helpMenuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
  1439.         TkpDestroyMenu(helpMenuPtr);
  1440.         TkpNewMenu(helpMenuPtr);
  1441.         helpMenuPtr->menuFlags &= ~MENU_HELP_MENU;
  1442.         helpMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  1443.         Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
  1444.             (ClientData) helpMenuPtr);
  1445.     }
  1446.     
  1447.     /*
  1448.      * We need to find the clone of this menu that is the menubar.
  1449.      * Once we do that, for every cascade in the menu, we need to 
  1450.      * insert the Mac menu in the Mac menubar. Finally, we need
  1451.      * to redraw the menubar.
  1452.      */
  1453.  
  1454.     menuRefPtr = NULL;
  1455.     if (currentMenuBarName != NULL) {
  1456.         menuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
  1457.             currentMenuBarName);
  1458.     }
  1459.     if (menuRefPtr != NULL) {
  1460.         TkMenu *menuPtr, *menuBarPtr;
  1461.         TkMenu *cascadeMenuPtr;
  1462.         char *appleMenuName, *helpMenuName;
  1463.         int appleIndex = -1, helpIndex = -1;
  1464.         int i;
  1465.         
  1466.         menuPtr = menuRefPtr->menuPtr;
  1467.         if (menuPtr != NULL) {
  1468.             TkMenuReferences *specialMenuRefPtr;
  1469.             TkMenuEntry *specialEntryPtr;
  1470.             
  1471.             appleMenuName = ckalloc(strlen(currentMenuBarName)
  1472.                     + 1 + strlen(".apple") + 1);
  1473.             sprintf(appleMenuName, "%s.apple", 
  1474.                     Tk_PathName(menuPtr->tkwin));
  1475.             specialMenuRefPtr = TkFindMenuReferences(currentMenuBarInterp, 
  1476.                     appleMenuName);
  1477.             if ((specialMenuRefPtr != NULL) 
  1478.                     && (specialMenuRefPtr->menuPtr != NULL)) {
  1479.                 for (specialEntryPtr 
  1480.                     = specialMenuRefPtr->parentEntryPtr;
  1481.                     specialEntryPtr != NULL;
  1482.                     specialEntryPtr 
  1483.                     = specialEntryPtr->nextCascadePtr) {
  1484.             if (specialEntryPtr->menuPtr == menuPtr) {
  1485.                 appleIndex = specialEntryPtr->index;
  1486.                 break;
  1487.             }
  1488.         }
  1489.         }                                        
  1490.             ckfree(appleMenuName);
  1491.             
  1492.             helpMenuName = ckalloc(strlen(currentMenuBarName)
  1493.                     + 1 + strlen(".help") + 1);
  1494.             sprintf(helpMenuName, "%s.help", 
  1495.                     Tk_PathName(menuPtr->tkwin));
  1496.             specialMenuRefPtr = TkFindMenuReferences(currentMenuBarInterp, 
  1497.                     helpMenuName);
  1498.             if ((specialMenuRefPtr != NULL)
  1499.                     && (specialMenuRefPtr->menuPtr != NULL)) {
  1500.                 for (specialEntryPtr 
  1501.                     = specialMenuRefPtr->parentEntryPtr;
  1502.                     specialEntryPtr != NULL;
  1503.                     specialEntryPtr 
  1504.                     = specialEntryPtr->nextCascadePtr) {
  1505.             if (specialEntryPtr->menuPtr == menuPtr) {
  1506.                 helpIndex = specialEntryPtr->index;
  1507.                 break;
  1508.             }
  1509.         }
  1510.         }
  1511.         ckfree(helpMenuName);  
  1512.                 
  1513.         }
  1514.         
  1515.         for (menuBarPtr = menuPtr; 
  1516.             (menuBarPtr != NULL) 
  1517.             && (menuBarPtr->menuType != MENUBAR);
  1518.             menuBarPtr = menuBarPtr->nextInstancePtr) {
  1519.         
  1520.             /*
  1521.              * Null loop body.
  1522.              */
  1523.              
  1524.         }
  1525.         
  1526.         if (menuBarPtr == NULL) {
  1527.             SetDefaultMenubar();
  1528.         } else {            
  1529.         if (menuBarPtr->tearOff != menuPtr->tearOff) {
  1530.             if (menuBarPtr->tearOff) {
  1531.                 appleIndex = (-1 == appleIndex) ? appleIndex
  1532.                         : appleIndex + 1;
  1533.                 helpIndex = (-1 == helpIndex) ? helpIndex
  1534.                         : helpIndex + 1;
  1535.             } else {
  1536.                 appleIndex = (-1 == appleIndex) ? appleIndex
  1537.                         : appleIndex - 1;
  1538.                 helpIndex = (-1 == helpIndex) ? helpIndex
  1539.                         : helpIndex - 1;
  1540.             }
  1541.         }
  1542.         ClearMenuBar();
  1543.         
  1544.         if (appleIndex == -1) {
  1545.             InsertMenu(tkAppleMenu, 0);
  1546.             currentAppleMenuID = 0;
  1547.         } else {
  1548.             short appleID;
  1549.                 appleMenuPtr = menuBarPtr->entries[appleIndex]
  1550.                         ->childMenuRefPtr->menuPtr;
  1551.         TkpDestroyMenu(appleMenuPtr);
  1552.             GetNewID(appleMenuPtr->interp, appleMenuPtr, 0, 
  1553.                 &appleID);
  1554.             macMenuHdl = NewMenu(appleID, "\p\024");
  1555.             appleMenuPtr->platformData = 
  1556.                 (TkMenuPlatformData) ckalloc(sizeof(MacMenu));
  1557.             ((MacMenu *)appleMenuPtr->platformData)->menuHdl
  1558.                 = macMenuHdl;
  1559.             SetRect(&((MacMenu *) appleMenuPtr->platformData)->menuRect,
  1560.                 0, 0, 0, 0);
  1561.                 appleMenuPtr->menuFlags |= MENU_APPLE_MENU;
  1562.                 if (!(appleMenuPtr->menuFlags 
  1563.                     & MENU_RECONFIGURE_PENDING)) {
  1564.                     appleMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
  1565.                     Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
  1566.                             (ClientData) appleMenuPtr);
  1567.                 }
  1568.                 InsertMenu(macMenuHdl, 0);
  1569.                 RecursivelyInsertMenu(appleMenuPtr);
  1570.                 currentAppleMenuID = appleID;
  1571.         }
  1572.         if (helpIndex == -1) {
  1573.             currentHelpMenuID = 0;
  1574.         }
  1575.         
  1576.         for (i = 0; i < menuBarPtr->numEntries; i++) {
  1577.             if (i == appleIndex) {
  1578.                 if (menuBarPtr->entries[i]->state == tkDisabledUid) {
  1579.                     DisableItem(((MacMenu *) menuBarPtr->entries[i]
  1580.                         ->childMenuRefPtr->menuPtr
  1581.                         ->platformData)->menuHdl,
  1582.                         0);
  1583.                 } else {
  1584.                     EnableItem(((MacMenu *) menuBarPtr->entries[i]
  1585.                         ->childMenuRefPtr->menuPtr
  1586.                         ->platformData)->menuHdl,
  1587.                         0);
  1588.             }                    
  1589.                 continue;
  1590.             } else if (i == helpIndex) {
  1591.                 TkMenu *helpMenuPtr = menuBarPtr->entries[i]
  1592.                         ->childMenuRefPtr->menuPtr;
  1593.                 MenuHandle helpMenuHdl = NULL;
  1594.                 
  1595.                 if (helpMenuPtr == NULL) {
  1596.                     continue;
  1597.                 }
  1598.                 helpMenuPtr->menuFlags |= MENU_HELP_MENU;
  1599.                 if (!(helpMenuPtr->menuFlags
  1600.                         & MENU_RECONFIGURE_PENDING)) {
  1601.                     helpMenuPtr->menuFlags 
  1602.                         |= MENU_RECONFIGURE_PENDING;
  1603.                     Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
  1604.                         (ClientData) helpMenuPtr);
  1605.                 }
  1606.                 macMenuHdl = 
  1607.                         ((MacMenu *) helpMenuPtr->platformData)->menuHdl;
  1608.                 currentHelpMenuID = (*macMenuHdl)->menuID;
  1609.             } else if (menuBarPtr->entries[i]->type 
  1610.                 == CASCADE_ENTRY) {
  1611.                 if ((menuBarPtr->entries[i]->childMenuRefPtr != NULL)
  1612.                     && menuBarPtr->entries[i]->childMenuRefPtr
  1613.                 ->menuPtr != NULL) {
  1614.                     cascadeMenuPtr = menuBarPtr->entries[i]
  1615.                     ->childMenuRefPtr->menuPtr;
  1616.                     macMenuHdl = ((MacMenu *) cascadeMenuPtr
  1617.                         ->platformData)->menuHdl;
  1618.                 DeleteMenu((*macMenuHdl)->menuID);
  1619.                     InsertMenu(macMenuHdl, 0);
  1620.                     RecursivelyInsertMenu(cascadeMenuPtr);
  1621.                     if (menuBarPtr->entries[i]->state == tkDisabledUid) {
  1622.                         DisableItem(((MacMenu *) menuBarPtr->entries[i]
  1623.                                 ->childMenuRefPtr->menuPtr
  1624.                                 ->platformData)->menuHdl,
  1625.                     0);
  1626.                     } else {
  1627.                         EnableItem(((MacMenu *) menuBarPtr->entries[i]
  1628.                                 ->childMenuRefPtr->menuPtr
  1629.                                 ->platformData)->menuHdl,
  1630.                     0);
  1631.                      }
  1632.                 }
  1633.             }
  1634.         }
  1635.     }
  1636.     } else {
  1637.         SetDefaultMenubar();
  1638.     }
  1639.     DrawMenuBar();
  1640.     menuBarFlags &= ~MENUBAR_REDRAW_PENDING;
  1641. }
  1642.  
  1643.  
  1644. /*
  1645.  *----------------------------------------------------------------------
  1646.  *
  1647.  * RecursivelyInsertMenu --
  1648.  *
  1649.  *    Puts all of the cascades of this menu in the Mac hierarchical list.
  1650.  *
  1651.  *
  1652.  * Results:
  1653.  *    None.
  1654.  *
  1655.  * Side effects:
  1656.  *    The menubar is changed.
  1657.  *
  1658.  *----------------------------------------------------------------------
  1659.  */
  1660.  
  1661. static void
  1662. RecursivelyInsertMenu(
  1663.     TkMenu *menuPtr)        /* All of the cascade items in this menu
  1664.                      * will be inserted into the mac menubar. */
  1665. {
  1666.     int i;
  1667.     TkMenu *cascadeMenuPtr;
  1668.     MenuHandle macMenuHdl;
  1669.     
  1670.     for (i = 0; i < menuPtr->numEntries; i++) {
  1671.         if (menuPtr->entries[i]->type == CASCADE_ENTRY) {
  1672.             if ((menuPtr->entries[i]->childMenuRefPtr != NULL)
  1673.                     && (menuPtr->entries[i]->childMenuRefPtr->menuPtr
  1674.             != NULL)) {
  1675.                 cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr;
  1676.             macMenuHdl = ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl;
  1677.             InsertMenu(macMenuHdl, -1);
  1678.             RecursivelyInsertMenu(cascadeMenuPtr);
  1679.         }
  1680.         }
  1681.     }
  1682. }
  1683.  
  1684. /*
  1685.  *----------------------------------------------------------------------
  1686.  *
  1687.  * RecursivelyDeleteMenu --
  1688.  *
  1689.  *    Takes all of the cascades of this menu out of the Mac hierarchical
  1690.  *    list.
  1691.  *
  1692.  *
  1693.  * Results:
  1694.  *    None.
  1695.  *
  1696.  * Side effects:
  1697.  *    The menubar is changed.
  1698.  *
  1699.  *----------------------------------------------------------------------
  1700.  */
  1701.  
  1702. static void
  1703. RecursivelyDeleteMenu(
  1704.     TkMenu *menuPtr)        /* All of the cascade items in this menu
  1705.                      * will be inserted into the mac menubar. */
  1706. {
  1707.     int i;
  1708.     TkMenu *cascadeMenuPtr;
  1709.     MenuHandle macMenuHdl;
  1710.     
  1711.     for (i = 0; i < menuPtr->numEntries; i++) {
  1712.         if (menuPtr->entries[i]->type == CASCADE_ENTRY) {
  1713.             if ((menuPtr->entries[i]->childMenuRefPtr != NULL)
  1714.                     && (menuPtr->entries[i]->childMenuRefPtr->menuPtr
  1715.             != NULL)) {
  1716.                 cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr;
  1717.             macMenuHdl = ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl;
  1718.             DeleteMenu((*macMenuHdl)->menuID);
  1719.             RecursivelyInsertMenu(cascadeMenuPtr);
  1720.         }
  1721.         }
  1722.     }
  1723. }
  1724.  
  1725. /*
  1726.  *----------------------------------------------------------------------
  1727.  *
  1728.  * SetDefaultMenubar --
  1729.  *
  1730.  *    Puts the Apple, File and Edit menus into the Macintosh menubar.
  1731.  *
  1732.  * Results:
  1733.  *    None.
  1734.  *
  1735.  * Side effects:
  1736.  *    The menubar is changed.
  1737.  *
  1738.  *----------------------------------------------------------------------
  1739.  */
  1740.  
  1741. static void
  1742. SetDefaultMenubar()
  1743. {
  1744.     if (currentMenuBarName != NULL) {
  1745.         ckfree(currentMenuBarName);
  1746.         currentMenuBarName = NULL;
  1747.     }
  1748.     currentMenuBarOwner = NULL;
  1749.     ClearMenuBar();
  1750.     InsertMenu(tkAppleMenu, 0);
  1751.     InsertMenu(tkFileMenu, 0);
  1752.     InsertMenu(tkEditMenu, 0);
  1753.     if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
  1754.         Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL);
  1755.         menuBarFlags |= MENUBAR_REDRAW_PENDING;
  1756.     }
  1757. }
  1758.  
  1759. /*
  1760.  *----------------------------------------------------------------------
  1761.  *
  1762.  * TkpSetMainMenubar --
  1763.  *
  1764.  *    Puts the menu associated with a window into the menubar. Should
  1765.  *    only be called when the window is in front.
  1766.  *
  1767.  * Results:
  1768.  *    None.
  1769.  *
  1770.  * Side effects:
  1771.  *    The menubar is changed.
  1772.  *
  1773.  *----------------------------------------------------------------------
  1774.  */
  1775.  
  1776. void
  1777. TkpSetMainMenubar(
  1778.     Tcl_Interp *interp,        /* The interpreter of the application */
  1779.     Tk_Window tkwin,        /* The frame we are setting up */
  1780.     char *menuName)        /* The name of the menu to put in front.
  1781.                      * If NULL, use the default menu bar.
  1782.                      */
  1783. {
  1784.     TkWindow *winPtr = (TkWindow *) tkwin;
  1785.     WindowRef macWindowPtr = (WindowRef) TkMacGetDrawablePort(winPtr->window);
  1786.     
  1787.     if ((macWindowPtr == NULL) || (macWindowPtr != FrontWindow())) {
  1788.         return;
  1789.     }
  1790.  
  1791.     if ((currentMenuBarInterp != interp) 
  1792.             || (currentMenuBarOwner != tkwin) 
  1793.             || (currentMenuBarName == NULL)
  1794.             || (menuName == NULL) 
  1795.             || (strcmp(menuName, currentMenuBarName) != 0)) {        
  1796.     Tk_Window searchWindow;
  1797.         TopLevelMenubarList *listPtr;
  1798.                     
  1799.         if (currentMenuBarName != NULL) {
  1800.             ckfree(currentMenuBarName);
  1801.         }
  1802.  
  1803.     if (menuName == NULL) {
  1804.         searchWindow = tkwin;
  1805.         if (strcmp(Tk_Class(searchWindow), "Menu") == 0) {
  1806.             TkMenuReferences *menuRefPtr;
  1807.                 
  1808.             menuRefPtr = TkFindMenuReferences(interp, Tk_PathName(tkwin));
  1809.             if (menuRefPtr != NULL) {
  1810.                 TkMenu *menuPtr = menuRefPtr->menuPtr;
  1811.                 if (menuPtr != NULL) {
  1812.                     menuPtr = menuPtr->masterMenuPtr;
  1813.                     searchWindow = menuPtr->tkwin;
  1814.                 }
  1815.             }
  1816.         } 
  1817.         for (; searchWindow != NULL;
  1818.             searchWindow = Tk_Parent(searchWindow)) {
  1819.             
  1820.             for (listPtr = windowListPtr; listPtr != NULL;
  1821.                 listPtr = listPtr->nextPtr) {
  1822.                 if (listPtr->tkwin == searchWindow) {
  1823.                     break;
  1824.                 }
  1825.             }
  1826.             if (listPtr != NULL) {
  1827.                 menuName = Tk_PathName(listPtr->menuPtr->masterMenuPtr->tkwin);
  1828.                 break;
  1829.             }
  1830.         }
  1831.     }
  1832.     
  1833.     if (menuName == NULL) {
  1834.         currentMenuBarName = NULL;
  1835.     } else {            
  1836.             currentMenuBarName = ckalloc(strlen(menuName) + 1);
  1837.         }
  1838.         currentMenuBarOwner = tkwin;
  1839.         currentMenuBarInterp = interp;
  1840.         strcpy(currentMenuBarName, menuName);
  1841.     }
  1842.     if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
  1843.         Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL);
  1844.         menuBarFlags |= MENUBAR_REDRAW_PENDING;
  1845.     }
  1846. }
  1847.  
  1848. /*
  1849.  *----------------------------------------------------------------------
  1850.  *
  1851.  * TkpSetWindowMenuBar --
  1852.  *
  1853.  *    Associates a given menu with a window.
  1854.  *
  1855.  * Results:
  1856.  *    None.
  1857.  *
  1858.  * Side effects:
  1859.  *    On Windows and UNIX, associates the platform menu with the
  1860.  *    platform window.
  1861.  *
  1862.  *----------------------------------------------------------------------
  1863.  */
  1864.  
  1865. void
  1866. TkpSetWindowMenuBar(
  1867.     Tk_Window tkwin,        /* The window we are setting the menu in */
  1868.     TkMenu *menuPtr)        /* The menu we are setting */
  1869. {
  1870.     TopLevelMenubarList *listPtr, *prevPtr;
  1871.     
  1872.     /*
  1873.      * Remove any existing reference to this window.
  1874.      */
  1875.     
  1876.     for (prevPtr = NULL, listPtr = windowListPtr; 
  1877.             listPtr != NULL; 
  1878.             prevPtr = listPtr, listPtr = listPtr->nextPtr) {
  1879.     if (listPtr->tkwin == tkwin) {
  1880.         break;
  1881.     }         
  1882.     }
  1883.     
  1884.     if (listPtr != NULL) {
  1885.         if (prevPtr != NULL) {
  1886.             prevPtr->nextPtr = listPtr->nextPtr;
  1887.         } else {
  1888.             windowListPtr = listPtr->nextPtr;
  1889.         }
  1890.         ckfree((char *) listPtr);
  1891.     }
  1892.     
  1893.     if (menuPtr != NULL) {
  1894.         listPtr = (TopLevelMenubarList *) ckalloc(sizeof(TopLevelMenubarList));
  1895.         listPtr->nextPtr = windowListPtr;
  1896.         windowListPtr = listPtr;
  1897.         listPtr->tkwin = tkwin;
  1898.         listPtr->menuPtr = menuPtr;
  1899.     }
  1900. }
  1901.  
  1902. /*
  1903.  *----------------------------------------------------------------------
  1904.  *
  1905.  * TkMacDispatchMenuEvent --
  1906.  *
  1907.  *    Given a menu id and an item, dispatches the command associated
  1908.  *    with it.
  1909.  *
  1910.  * Results:
  1911.  *    None.
  1912.  *
  1913.  * Side effects:
  1914.  *    Commands get executed.
  1915.  *
  1916.  *----------------------------------------------------------------------
  1917.  */
  1918.  
  1919. int
  1920. TkMacDispatchMenuEvent(
  1921.     int menuID,        /* The menu id of the menu we are invoking */
  1922.     int index)        /* The one-based index of the item that was 
  1923.                          * selected. */
  1924. {
  1925.     int result = TCL_OK;
  1926.     if (menuID != 0) {
  1927.         if (menuID == kHMHelpMenuID) {
  1928.             if (currentMenuBarOwner != NULL) {
  1929.                 TkMenuReferences *helpMenuRef;
  1930.                 char *helpMenuName = ckalloc(strlen(currentMenuBarName)
  1931.                     + strlen(".help") + 1);
  1932.                 sprintf(helpMenuName, "%s.help", currentMenuBarName);
  1933.                 helpMenuRef = TkFindMenuReferences(currentMenuBarInterp,
  1934.                     helpMenuName);
  1935.                 ckfree(helpMenuName);
  1936.                 if ((helpMenuRef != NULL) && (helpMenuRef->menuPtr != NULL)) {
  1937.                     int newIndex = index - helpItemCount - 1;
  1938.                     result = TkInvokeMenu(currentMenuBarInterp,
  1939.                             helpMenuRef->menuPtr, newIndex);
  1940.                 }
  1941.             }
  1942.         } else {
  1943.         Tcl_HashEntry *commandEntryPtr = 
  1944.                 Tcl_FindHashEntry(&commandTable, (char *) menuID);
  1945.         TkMenu *menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr);
  1946.         if ((currentAppleMenuID == menuID) 
  1947.                 && (index > menuPtr->numEntries + 1)) {
  1948.             Str255 itemText;
  1949.             
  1950.             GetMenuItemText(GetMenuHandle(menuID), index, itemText);
  1951.             OpenDeskAcc(itemText);
  1952.             result = TCL_OK;
  1953.         } else {
  1954.             result = TkInvokeMenu(menuPtr->interp, menuPtr, index - 1);
  1955.         }
  1956.     }
  1957.     }
  1958.     return result;
  1959. }
  1960.  
  1961. /*
  1962.  *----------------------------------------------------------------------
  1963.  *
  1964.  * GetMenuIndicatorGeometry --
  1965.  *
  1966.  *    Gets the width and height of the indicator area of a menu.
  1967.  *
  1968.  * Results:
  1969.  *    widthPtr and heightPtr are set.
  1970.  *
  1971.  * Side effects:
  1972.  *    None.
  1973.  *
  1974.  *----------------------------------------------------------------------
  1975.  */
  1976.  
  1977. static void
  1978. GetMenuIndicatorGeometry (
  1979.     TkMenu *menuPtr,            /* The menu we are drawing */
  1980.     TkMenuEntry *mePtr,            /* The entry we are measuring */
  1981.     Tk_Font tkfont,            /* Precalculated font */
  1982.     CONST Tk_FontMetrics *fmPtr,    /* Precalculated font metrics */
  1983.     int *widthPtr,            /* The resulting width */
  1984.     int *heightPtr)            /* The resulting height */
  1985. {
  1986.     char markChar;
  1987.     
  1988.     *heightPtr = fmPtr->linespace;
  1989.  
  1990.     markChar = (char) FindMarkCharacter(mePtr);
  1991.     *widthPtr = Tk_TextWidth(tkfont, &markChar, 1) + 4;
  1992. }
  1993.  
  1994. /*
  1995.  *----------------------------------------------------------------------
  1996.  *
  1997.  * GetMenuAccelGeometry --
  1998.  *
  1999.  *    Gets the width and height of the accelerator area of a menu.
  2000.  *
  2001.  * Results:
  2002.  *    widthPtr and heightPtr are set.
  2003.  *
  2004.  * Side effects:
  2005.  *    None.
  2006.  *
  2007.  *----------------------------------------------------------------------
  2008.  */
  2009.  
  2010. static void
  2011. GetMenuAccelGeometry (
  2012.     TkMenu *menuPtr,            /* The menu we are measuring */
  2013.     TkMenuEntry *mePtr,            /* The entry we are measuring */
  2014.     Tk_Font tkfont,            /* The precalculated font */
  2015.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2016.     int *modWidthPtr,            /* The width of all of the key
  2017.                          * modifier symbols. */
  2018.     int *textWidthPtr,            /* The resulting width */
  2019.     int *heightPtr)            /* The resulting height */
  2020. {
  2021.     *heightPtr = fmPtr->linespace;
  2022.     *modWidthPtr = 0;
  2023.     if (mePtr->type == CASCADE_ENTRY) {
  2024.         *textWidthPtr = SICN_HEIGHT;
  2025.         *modWidthPtr = Tk_TextWidth(tkfont, "W", 1);
  2026.     } else if (0 == mePtr->accelLength) {
  2027.         *textWidthPtr = 0;
  2028.     } else {
  2029.         
  2030.         if (NULL == GetResource('SICN', SICN_RESOURCE_NUMBER)) {
  2031.             *textWidthPtr = Tk_TextWidth(tkfont, mePtr->accel,
  2032.                     mePtr->accelLength);
  2033.         } else {
  2034.             int emWidth = Tk_TextWidth(tkfont, "W", 1) + 1;
  2035.             if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) {
  2036.                 int width = Tk_TextWidth(tkfont, mePtr->accel,
  2037.                     mePtr->accelLength);
  2038.                 *textWidthPtr = emWidth;
  2039.                 if (width < emWidth) {
  2040.                     *modWidthPtr = 0;
  2041.                 } else {
  2042.                     *modWidthPtr = width - emWidth;
  2043.                 }   
  2044.             } else {
  2045.                 int length = ((EntryGeometry *)mePtr->platformEntryData)
  2046.                         ->accelTextStart;
  2047.                 if (mePtr->entryFlags & ENTRY_CONTROL_ACCEL) {
  2048.                     *modWidthPtr += CONTROL_ICON_WIDTH;
  2049.                 }
  2050.                 if (mePtr->entryFlags & ENTRY_SHIFT_ACCEL) {
  2051.                     *modWidthPtr += SHIFT_ICON_WIDTH;
  2052.                 }
  2053.                 if (mePtr->entryFlags & ENTRY_OPTION_ACCEL) {
  2054.                     *modWidthPtr += OPTION_ICON_WIDTH;
  2055.                 }
  2056.                 if (mePtr->entryFlags & ENTRY_COMMAND_ACCEL) {
  2057.                     *modWidthPtr += COMMAND_ICON_WIDTH;
  2058.                 }
  2059.                 if (1 == (mePtr->accelLength - length)) {
  2060.                     *textWidthPtr = emWidth;
  2061.                 } else {
  2062.                     *textWidthPtr += Tk_TextWidth(tkfont, mePtr->accel 
  2063.                         + length, mePtr->accelLength - length);
  2064.             }
  2065.             }
  2066.         }
  2067.     }
  2068. }
  2069.  
  2070. /*
  2071.  *----------------------------------------------------------------------
  2072.  *
  2073.  * GetTearoffEntryGeometry --
  2074.  *
  2075.  *    Gets the width and height of of a tearoff entry.
  2076.  *
  2077.  * Results:
  2078.  *    widthPtr and heightPtr are set.
  2079.  *
  2080.  * Side effects:
  2081.  *    None.
  2082.  *
  2083.  *----------------------------------------------------------------------
  2084.  */
  2085.  
  2086. static void
  2087. GetTearoffEntryGeometry (
  2088.     TkMenu *menuPtr,            /* The menu we are drawing */
  2089.     TkMenuEntry *mePtr,            /* The entry we are measuring */
  2090.     Tk_Font tkfont,            /* The precalculated font */
  2091.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2092.     int *widthPtr,            /* The resulting width */
  2093.     int *heightPtr)            /* The resulting height */
  2094. {
  2095.     if ((GetResource('MDEF', 591) == NULL) &&
  2096.         (menuPtr->menuType == MASTER_MENU)) {
  2097.         *heightPtr = fmPtr->linespace;
  2098.         *widthPtr = 0;
  2099.     } else {
  2100.     *widthPtr = *heightPtr = 0;
  2101.     }
  2102. }
  2103.  
  2104. /*
  2105.  *----------------------------------------------------------------------
  2106.  *
  2107.  * GetMenuSeparatorGeometry --
  2108.  *
  2109.  *    Gets the width and height of menu separator.
  2110.  *
  2111.  * Results:
  2112.  *    widthPtr and heightPtr are set.
  2113.  *
  2114.  * Side effects:
  2115.  *    None.
  2116.  *
  2117.  *----------------------------------------------------------------------
  2118.  */
  2119.  
  2120. static void
  2121. GetMenuSeparatorGeometry(
  2122.     TkMenu *menuPtr,            /* The menu we are drawing */
  2123.     TkMenuEntry *mePtr,            /* The entry we are measuring */
  2124.     Tk_Font tkfont,            /* The precalculated font */
  2125.     CONST Tk_FontMetrics *fmPtr,    /* The precalcualted font metrics */
  2126.     int *widthPtr,            /* The resulting width */
  2127.     int *heightPtr)            /* The resulting height */
  2128. {
  2129.     *widthPtr = 0;
  2130.     *heightPtr = fmPtr->linespace;
  2131. }
  2132.  
  2133. /*
  2134.  *----------------------------------------------------------------------
  2135.  *
  2136.  * DrawMenuEntryIndicator --
  2137.  *
  2138.  *    This procedure draws the indicator part of a menu.
  2139.  *
  2140.  * Results:
  2141.  *    None.
  2142.  *
  2143.  * Side effects:
  2144.  *    Commands are output to X to display the menu in its
  2145.  *    current mode.
  2146.  *
  2147.  *----------------------------------------------------------------------
  2148.  */
  2149.  
  2150. static void
  2151. DrawMenuEntryIndicator(
  2152.     TkMenu *menuPtr,            /* The menu we are drawing */
  2153.     TkMenuEntry *mePtr,            /* The entry we are drawing */
  2154.     Drawable d,                /* The drawable we are drawing */
  2155.     GC gc,                /* The GC we are drawing with */
  2156.     GC indicatorGC,            /* The GC to use for the indicator */
  2157.     Tk_Font tkfont,            /* The precalculated font */
  2158.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2159.     int x,                /* topleft hand corner of entry */
  2160.     int y,                /* topleft hand corner of entry */
  2161.     int width,                /* width of entry */
  2162.     int height)                /* height of entry */
  2163. {
  2164.     if (((mePtr->type == CHECK_BUTTON_ENTRY) || 
  2165.             (mePtr->type == RADIO_BUTTON_ENTRY))
  2166.         && (mePtr->indicatorOn)
  2167.             && (mePtr->entryFlags & ENTRY_SELECTED)) {
  2168.     int baseline;
  2169.     short markShort;
  2170.     char markChar;
  2171.     
  2172.         baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
  2173.         GetItemMark(((MacMenu *) menuPtr->platformData)->menuHdl,
  2174.             mePtr->index + 1, &markShort);
  2175.         if (markShort != 0) {
  2176.             markChar = (char) markShort;
  2177.             Tk_DrawChars(menuPtr->display, d, gc, tkfont, &markChar, 1,
  2178.                     x + 2, baseline);
  2179.     }
  2180.     }    
  2181. }
  2182.  
  2183. /*
  2184.  *----------------------------------------------------------------------
  2185.  *
  2186.  * DrawSICN --
  2187.  *
  2188.  *    Given a resource id and an index, loads the appropriate SICN
  2189.  *    and draws it into a given drawable using the given gc.
  2190.  *
  2191.  * Results:
  2192.  *    Returns 1 if the SICN was found, 0 if not found.
  2193.  *
  2194.  * Side effects:
  2195.  *    Commands are output to X to display the menu in its
  2196.  *    current mode.
  2197.  *
  2198.  *----------------------------------------------------------------------
  2199.  */
  2200. static int
  2201. DrawSICN(
  2202.     int resourceID,            /* The resource # of the SICN table */
  2203.     int index,                /* The index into the SICN table of the
  2204.                          * icon we want. */
  2205.     Drawable d,                /* What we are drawing into */
  2206.     GC gc,                /* The GC to draw with */
  2207.     int x,                /* The left hand coord of the SICN */
  2208.     int y)                /* The top coord of the SICN */
  2209. {
  2210.     Handle sicnHandle = (Handle) GetResource('SICN', SICN_RESOURCE_NUMBER);
  2211.     
  2212.     if (NULL == sicnHandle) {
  2213.         return 0;
  2214.     } else {
  2215.         BitMap sicnBitmap;
  2216.     Rect destRect;
  2217.     CGrafPtr saveWorld;
  2218.     GDHandle saveDevice;
  2219.     GWorldPtr destPort;
  2220.     BitMapPtr destBitMap;
  2221.     RGBColor origForeColor, origBackColor, foreColor, backColor;
  2222.  
  2223.     HLock(sicnHandle);
  2224.     destPort = TkMacGetDrawablePort(d);
  2225.     GetGWorld(&saveWorld, &saveDevice);
  2226.     SetGWorld(destPort, NULL);
  2227.     TkMacSetUpClippingRgn(d);
  2228.     TkMacSetUpGraphicsPort(gc);
  2229.     GetForeColor(&origForeColor);
  2230.     GetBackColor(&origBackColor);
  2231.     
  2232.     if (TkSetMacColor(gc->foreground, &foreColor) == true) {
  2233.         RGBForeColor(&foreColor);
  2234.     }
  2235.     
  2236.     if (TkSetMacColor(gc->background, &backColor) == true) {
  2237.         RGBBackColor(&backColor);
  2238.     }
  2239.  
  2240.     SetRect(&destRect, x, y, x + SICN_HEIGHT, y + SICN_HEIGHT);
  2241.     sicnBitmap.baseAddr = (Ptr) (*sicnHandle) + index * SICN_HEIGHT
  2242.         * SICN_ROWS;
  2243.     sicnBitmap.rowBytes = SICN_ROWS;
  2244.     SetRect(&sicnBitmap.bounds, 0, 0, 16, 16);
  2245.     destBitMap = &((GrafPtr) destPort)->portBits;
  2246.     CopyBits(&sicnBitmap, destBitMap, &sicnBitmap.bounds, &destRect, 
  2247.         destPort->txMode, NULL);
  2248.     HUnlock(sicnHandle);
  2249.     RGBForeColor(&origForeColor);
  2250.     RGBBackColor(&origBackColor);
  2251.     SetGWorld(saveWorld, saveDevice);    
  2252.         return 1;
  2253.     }
  2254. }
  2255.  
  2256. /*
  2257.  *----------------------------------------------------------------------
  2258.  *
  2259.  * DrawMenuEntryAccelerator --
  2260.  *
  2261.  *    This procedure draws the accelerator part of a menu. We
  2262.  *    need to decide what to draw here. Should we replace strings
  2263.  *    like "Control", "Command", etc?
  2264.  *
  2265.  * Results:
  2266.  *    None.
  2267.  *
  2268.  * Side effects:
  2269.  *    Commands are output to X to display the menu in its
  2270.  *    current mode.
  2271.  *
  2272.  *----------------------------------------------------------------------
  2273.  */
  2274.  
  2275. static void
  2276. DrawMenuEntryAccelerator(
  2277.     TkMenu *menuPtr,            /* The menu we are drawing */
  2278.     TkMenuEntry *mePtr,            /* The entry we are drawing */
  2279.     Drawable d,                /* The drawable we are drawing in */
  2280.     GC gc,                /* The gc to draw into */
  2281.     Tk_Font tkfont,            /* The precalculated font */
  2282.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2283.     Tk_3DBorder activeBorder,        /* border for menu background */
  2284.     int x,                /* The left side of the entry */
  2285.     int y,                /* The top of the entry */
  2286.     int width,                /* The width of the entry */
  2287.     int height,                /* The height of the entry */
  2288.     int drawArrow)            /* Whether or not to draw cascade arrow */
  2289. {
  2290.     if (mePtr->type == CASCADE_ENTRY) {
  2291.         if (0 == DrawSICN(SICN_RESOURCE_NUMBER, CASCADE_ARROW, d, gc,
  2292.             x + width - SICN_HEIGHT, (y + (height / 2))
  2293.             - (SICN_HEIGHT / 2))) {
  2294.         XPoint points[3];
  2295.         Tk_Window tkwin = menuPtr->tkwin;
  2296.  
  2297.         if (mePtr->type == CASCADE_ENTRY) {
  2298.         points[0].x = width - menuPtr->activeBorderWidth
  2299.             - MAC_MARGIN_WIDTH - CASCADE_ARROW_WIDTH;
  2300.         points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2;
  2301.         points[1].x = points[0].x;
  2302.         points[1].y = points[0].y + CASCADE_ARROW_HEIGHT;
  2303.         points[2].x = points[0].x + CASCADE_ARROW_WIDTH;
  2304.         points[2].y = points[0].y + CASCADE_ARROW_HEIGHT/2;
  2305.         Tk_Fill3DPolygon(menuPtr->tkwin, d, activeBorder, points, 
  2306.             3, DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT);
  2307.         }
  2308.     }
  2309.     } else if (mePtr->accelLength != 0) {
  2310.         int leftEdge = x + width;
  2311.         int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
  2312.  
  2313.     if (NULL == GetResource('SICN', SICN_RESOURCE_NUMBER)) {
  2314.         leftEdge -= ((EntryGeometry *) mePtr->platformEntryData)
  2315.                 ->accelTextWidth;
  2316.         Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel,
  2317.                 mePtr->accelLength, leftEdge, baseline);
  2318.     } else {
  2319.         EntryGeometry *geometryPtr = 
  2320.                 (EntryGeometry *) mePtr->platformEntryData;
  2321.         int length = mePtr->accelLength - geometryPtr->accelTextStart;
  2322.         
  2323.         leftEdge -= geometryPtr->accelTextWidth;
  2324.         if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) {
  2325.             leftEdge -= geometryPtr->modifierWidth;
  2326.         }
  2327.         
  2328.         Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel 
  2329.             + geometryPtr->accelTextStart, length, leftEdge, baseline);
  2330.  
  2331.         if (mePtr->entryFlags & ENTRY_COMMAND_ACCEL) {
  2332.             leftEdge -= COMMAND_ICON_WIDTH;
  2333.             DrawSICN(SICN_RESOURCE_NUMBER, COMMAND_ICON, d, gc,
  2334.                 leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1);
  2335.         }
  2336.  
  2337.         if (mePtr->entryFlags & ENTRY_OPTION_ACCEL) {
  2338.             leftEdge -= OPTION_ICON_WIDTH;
  2339.             DrawSICN(SICN_RESOURCE_NUMBER, OPTION_ICON, d, gc,
  2340.                 leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1);
  2341.         }
  2342.  
  2343.         if (mePtr->entryFlags & ENTRY_SHIFT_ACCEL) {
  2344.             leftEdge -= SHIFT_ICON_WIDTH;
  2345.             DrawSICN(SICN_RESOURCE_NUMBER, SHIFT_ICON, d, gc,
  2346.                 leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1);
  2347.         }
  2348.  
  2349.         if (mePtr->entryFlags & ENTRY_CONTROL_ACCEL) {
  2350.             leftEdge -= CONTROL_ICON_WIDTH;
  2351.             DrawSICN(SICN_RESOURCE_NUMBER, CONTROL_ICON, d, gc,
  2352.                 leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1);
  2353.         }
  2354.         }
  2355.     }
  2356. }
  2357.  
  2358. /*
  2359.  *----------------------------------------------------------------------
  2360.  *
  2361.  * DrawMenuSeparator --
  2362.  *
  2363.  *    The menu separator is drawn.
  2364.  *
  2365.  * Results:
  2366.  *    None.
  2367.  *
  2368.  * Side effects:
  2369.  *    Commands are output to X to display the menu in its
  2370.  *    current mode.
  2371.  *
  2372.  *----------------------------------------------------------------------
  2373.  */
  2374.  
  2375. static void
  2376. DrawMenuSeparator(
  2377.     TkMenu *menuPtr,            /* The menu we are drawing */
  2378.     TkMenuEntry *mePtr,            /* The entry we are drawing */
  2379.     Drawable d,                /* The drawable we are drawing into */
  2380.     GC gc,                /* The gc we are drawing with */
  2381.     Tk_Font tkfont,            /* The precalculated font */
  2382.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  2383.     int x,                /* left coordinate of entry */
  2384.     int y,                /* top coordinate of entry */
  2385.     int width,                /* width of entry */
  2386.     int height)                /* height of entry */
  2387. {
  2388.     CGrafPtr saveWorld;
  2389.     GDHandle saveDevice;
  2390.     GWorldPtr destPort;
  2391.    
  2392.     destPort = TkMacGetDrawablePort(d);
  2393.     GetGWorld(&saveWorld, &saveDevice);
  2394.     SetGWorld(destPort, NULL);
  2395.     TkMacSetUpClippingRgn(d);
  2396.     
  2397.     /*
  2398.      * We don't want to use the text GC for drawing the separator. It
  2399.      * needs to be the same color as disabled items.
  2400.      */
  2401.     
  2402.     TkMacSetUpGraphicsPort(mePtr->disabledGC != None ? mePtr->disabledGC
  2403.             : menuPtr->disabledGC);
  2404.     
  2405.     MoveTo(x, y + (height / 2));
  2406.     Line(width, 0);
  2407.     
  2408.     SetGWorld(saveWorld, saveDevice);
  2409. }
  2410.  
  2411. /*
  2412.  *----------------------------------------------------------------------
  2413.  *
  2414.  * MenuDefProc --
  2415.  *
  2416.  *    This routine is the MDEF handler for Tk. It receives all messages
  2417.  *    for the menu and dispatches them.
  2418.  *
  2419.  * Results:
  2420.  *    None.
  2421.  *
  2422.  * Side effects:
  2423.  *    This routine causes menus to be drawn and will certainly allocate
  2424.  *    memory as a result. Also, the menu can scroll up and down, and
  2425.  *    various other interface actions can take place.
  2426.  *
  2427.  *----------------------------------------------------------------------
  2428.  */
  2429.  
  2430. static void
  2431. MenuDefProc(
  2432.     short message,            /* What action are we taking? */
  2433.     MenuHandle menu,            /* The menu we are working with */
  2434.     Rect *menuRectPtr,            /* A pointer to the rect for the
  2435.                          * whole menu. */
  2436.     Point hitPt,            /* Where the mouse was clicked for
  2437.                          * the appropriate messages. */
  2438.     short *whichItem,            /* Output result. Which item was
  2439.                          * hit by the user? */
  2440.     TkMenuLowMemGlobals *globalsPtr)    /* The low mem globals we have
  2441.                          * to change */
  2442. {
  2443. #define SCREEN_MARGIN 5
  2444.     TkMenu *menuPtr;
  2445.     TkMenuEntry *parentEntryPtr;
  2446.     Tcl_HashEntry *commandEntryPtr;
  2447.     GrafPtr windowMgrPort;
  2448.     Tk_Font tkfont;
  2449.     Tk_FontMetrics fontMetrics, entryMetrics;
  2450.     Tk_FontMetrics *fmPtr;
  2451.     TkMenuEntry *mePtr;
  2452.     int i;
  2453.     int maxMenuHeight;
  2454.     int oldItem;
  2455.     int newItem = -1;
  2456.     GDHandle device;
  2457.     Rect itemRect;
  2458.     short windowPart;
  2459.     WindowRef whichWindow;
  2460.     RGBColor bgColor;
  2461.     RGBColor fgColor;
  2462.     RGBColor origFgColor;
  2463.     PenState origPenState;
  2464.     Rect dragRect;
  2465.     Rect scratchRect = {-32768, -32768, 32767, 32767};
  2466.     RgnHandle oldClipRgn;
  2467.     TkMenuReferences *menuRefPtr;
  2468.     TkMenu *searchMenuPtr;
  2469.     Rect menuClipRect;
  2470.     
  2471.     HLock((Handle) menu);
  2472.     commandEntryPtr = Tcl_FindHashEntry(&commandTable,
  2473.             (char *) (*menu)->menuID);
  2474.     HUnlock((Handle) menu);
  2475.     menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr);
  2476.  
  2477.     switch (message) {
  2478.         case mSizeMsg:
  2479.         GetWMgrPort(&windowMgrPort);
  2480.             maxMenuHeight = windowMgrPort->portRect.bottom
  2481.                     - windowMgrPort->portRect.top
  2482.                     - GetMBarHeight() - SCREEN_MARGIN;
  2483.             (*menu)->menuWidth = menuPtr->totalWidth;
  2484.             (*menu)->menuHeight = maxMenuHeight < menuPtr->totalHeight ?
  2485.                     maxMenuHeight : menuPtr->totalHeight;
  2486.                break;
  2487.  
  2488.         case mDrawMsg:
  2489.         
  2490.             /*
  2491.              * Store away the menu rectangle so we can keep track of the
  2492.              * different regions that the menu obscures.
  2493.              */
  2494.             
  2495.             ((MacMenu *) menuPtr->platformData)->menuRect = *menuRectPtr;
  2496.         if (tkMenuCascadeRgn == NULL) {
  2497.         tkMenuCascadeRgn = NewRgn();
  2498.         }
  2499.         if (utilRgn == NULL) {
  2500.         utilRgn = NewRgn();
  2501.         }
  2502.         if (totalMenuRgn == NULL) {
  2503.             totalMenuRgn = NewRgn();
  2504.         }
  2505.             SetEmptyRgn(tkMenuCascadeRgn);
  2506.         for (searchMenuPtr = menuPtr; searchMenuPtr != NULL; ) {
  2507.         RectRgn(utilRgn, 
  2508.                 &((MacMenu *) searchMenuPtr->platformData)->menuRect);
  2509.         InsetRgn(utilRgn, -1, -1);
  2510.         UnionRgn(tkMenuCascadeRgn, utilRgn, tkMenuCascadeRgn);
  2511.         OffsetRgn(utilRgn, 1, 1);
  2512.         UnionRgn(tkMenuCascadeRgn, utilRgn, tkMenuCascadeRgn);
  2513.         
  2514.         if (searchMenuPtr->menuRefPtr->parentEntryPtr != NULL) {
  2515.             searchMenuPtr = searchMenuPtr->menuRefPtr
  2516.                 ->parentEntryPtr->menuPtr;
  2517.         } else {
  2518.             break;
  2519.         }
  2520.         if (searchMenuPtr->menuType == MENUBAR) {
  2521.             break;
  2522.         }
  2523.         }
  2524.         UnionRgn(totalMenuRgn, tkMenuCascadeRgn, totalMenuRgn);
  2525.         SetEmptyRgn(utilRgn);
  2526.         
  2527.         /*
  2528.          * Next, figure out scrolling information.
  2529.          */
  2530.         
  2531.             GetGWorld(&macMDEFDrawable.portPtr, &device);
  2532.         menuClipRect = *menuRectPtr;
  2533.         if ((menuClipRect.bottom - menuClipRect.top) 
  2534.                 < menuPtr->totalHeight) {
  2535.          if (globalsPtr->menuTop < menuRectPtr->top) {
  2536.              DrawSICN(SICN_RESOURCE_NUMBER, UP_ARROW, 
  2537.                      (Drawable) &macMDEFDrawable,
  2538.                      menuPtr->textGC, 
  2539.                      menuRectPtr->left 
  2540.                      + menuPtr->entries[1]->indicatorSpace,
  2541.                      menuRectPtr->top);
  2542.              menuClipRect.top += SICN_HEIGHT;
  2543.          }
  2544.          if ((globalsPtr->menuTop + menuPtr->totalHeight)
  2545.              > menuRectPtr->bottom) {
  2546.              DrawSICN(SICN_RESOURCE_NUMBER, DOWN_ARROW,
  2547.                      (Drawable) &macMDEFDrawable,
  2548.                      menuPtr->textGC, 
  2549.                      menuRectPtr->left 
  2550.                      + menuPtr->entries[1]->indicatorSpace,
  2551.                      menuRectPtr->bottom - SICN_HEIGHT);
  2552.              menuClipRect.bottom -= SICN_HEIGHT;
  2553.          }
  2554.          GetClip(utilRgn);
  2555.          ClipRect(&menuClipRect);
  2556.         }
  2557.         
  2558.         /*
  2559.          * Now, actually draw the menu. Don't draw entries that
  2560.          * are higher than the top arrow, and don't draw entries
  2561.          * that are lower than the bottom.
  2562.          */
  2563.         
  2564.         Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics);            
  2565.             for (i = 0; i < menuPtr->numEntries; i++) {
  2566.                 mePtr = menuPtr->entries[i];
  2567.                 if (globalsPtr->menuTop + mePtr->y + mePtr->height
  2568.                     < menuClipRect.top) {
  2569.                     continue;
  2570.                 } else if (globalsPtr->menuTop + mePtr->y
  2571.                     > menuClipRect.bottom) {
  2572.                     continue;
  2573.                 }
  2574.                 if (mePtr->tkfont == NULL) {
  2575.                     fmPtr = &fontMetrics;
  2576.                     tkfont = menuPtr->tkfont;
  2577.                 } else {
  2578.                     tkfont = mePtr->tkfont;
  2579.                     Tk_GetFontMetrics(tkfont, &entryMetrics);
  2580.                     fmPtr = &entryMetrics;
  2581.                 }
  2582.                 TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable,
  2583.                     tkfont, fmPtr, menuRectPtr->left + mePtr->x, 
  2584.                     globalsPtr->menuTop + mePtr->y,
  2585.                     (mePtr->entryFlags & ENTRY_LAST_COLUMN) ?
  2586.                     menuPtr->totalWidth - mePtr->x : mePtr->width,
  2587.                     menuPtr->entries[i]->height, 0, 1);
  2588.              }
  2589.              globalsPtr->menuBottom = globalsPtr->menuTop 
  2590.                      + menuPtr->totalHeight;
  2591.         if (!EmptyRgn(utilRgn)) {
  2592.             SetClip(utilRgn);
  2593.             SetEmptyRgn(utilRgn);
  2594.         }
  2595.         MDEFScrollFlag = 1;
  2596.             break;
  2597.  
  2598.         case mChooseMsg: {
  2599.             int hasTopScroll, hasBottomScroll;
  2600.             enum {
  2601.                 DONT_SCROLL, DOWN_SCROLL, UP_SCROLL
  2602.             } scrollDirection;
  2603.             Rect updateRect;
  2604.             short scrollAmt;
  2605.             RGBColor origForeColor, origBackColor, foreColor, backColor;
  2606.             
  2607.          GetGWorld(&macMDEFDrawable.portPtr, &device);
  2608.          GetForeColor(&origForeColor);
  2609.          GetBackColor(&origBackColor);
  2610.  
  2611.         if (TkSetMacColor(menuPtr->textGC->foreground, 
  2612.                 &foreColor) == true) {
  2613.             RGBForeColor(&foreColor);
  2614.         }
  2615.         if (TkSetMacColor(menuPtr->textGC->background, 
  2616.                 &backColor) == true) {
  2617.             RGBBackColor(&backColor);
  2618.         }
  2619.  
  2620.         /*
  2621.          * Find out which item was hit. If it is the same as the old item,
  2622.          * we don't need to do anything.
  2623.          */
  2624.  
  2625.         oldItem = *whichItem - 1;
  2626.          
  2627.         if (PtInRect(hitPt, menuRectPtr)) {
  2628.             for (i = 0; i < menuPtr->numEntries; i++) {
  2629.                 mePtr = menuPtr->entries[i];
  2630.                 itemRect.left = menuRectPtr->left + mePtr->x;
  2631.                 itemRect.top = globalsPtr->menuTop + mePtr->y;
  2632.                 if (mePtr->entryFlags & ENTRY_LAST_COLUMN) {
  2633.                     itemRect.right = itemRect.left + menuPtr->totalWidth
  2634.                         - mePtr->x;
  2635.                 } else {
  2636.                     itemRect.right = itemRect.left + mePtr->width;
  2637.                 }
  2638.                 itemRect.bottom = itemRect.top
  2639.                 + menuPtr->entries[i]->height;
  2640.                 if (PtInRect(hitPt, &itemRect)) {
  2641.                     if ((mePtr->type == SEPARATOR_ENTRY)
  2642.                         || (mePtr->state == tkDisabledUid)) {
  2643.                         newItem = -1;
  2644.                     } else {
  2645.                         TkMenuEntry *cascadeEntryPtr;
  2646.                         int parentDisabled = 0;
  2647.                         
  2648.                         for (cascadeEntryPtr
  2649.                     = menuPtr->menuRefPtr->parentEntryPtr;
  2650.                                 cascadeEntryPtr != NULL;
  2651.                                 cascadeEntryPtr 
  2652.                                 = cascadeEntryPtr->nextCascadePtr) {
  2653.                 if (strcmp(cascadeEntryPtr->name,
  2654.                     Tk_PathName(menuPtr->tkwin)) == 0) {
  2655.                     if (cascadeEntryPtr->state
  2656.                         == tkDisabledUid) {
  2657.                         parentDisabled = 1;
  2658.                     }
  2659.                     break;
  2660.                 }
  2661.                 }
  2662.                 if (parentDisabled) {
  2663.                     newItem = -1;
  2664.                 } else {                 
  2665.                             newItem = i;
  2666.                             if ((mePtr->type == CASCADE_ENTRY) 
  2667.                                 && (oldItem != newItem)) {
  2668.                             globalsPtr->itemRect = itemRect;
  2669.                         }
  2670.                     }
  2671.                     }
  2672.                     break;
  2673.                 }
  2674.             }
  2675.         }
  2676.  
  2677.         /*
  2678.          * Now we need to take care of scrolling the menu.
  2679.          */
  2680.         
  2681.         hasTopScroll = globalsPtr->menuTop < menuRectPtr->top;
  2682.         hasBottomScroll = globalsPtr->menuBottom > menuRectPtr->bottom;
  2683.         scrollDirection = DONT_SCROLL;
  2684.         if (hasTopScroll 
  2685.                 && (hitPt.v < menuRectPtr->top + SICN_HEIGHT)) {
  2686.         newItem = -1;
  2687.         scrollDirection = DOWN_SCROLL;
  2688.         } else if (hasBottomScroll
  2689.             && (hitPt.v > menuRectPtr->bottom - SICN_HEIGHT)) {
  2690.         newItem = -1;
  2691.         scrollDirection = UP_SCROLL;
  2692.         }            
  2693.         menuClipRect = *menuRectPtr;
  2694.         if (hasTopScroll) {
  2695.             menuClipRect.top += SICN_HEIGHT;
  2696.         }
  2697.         if (hasBottomScroll) {
  2698.             menuClipRect.bottom -= SICN_HEIGHT;
  2699.         }
  2700.         if (MDEFScrollFlag) {
  2701.             scrollDirection = DONT_SCROLL;
  2702.             MDEFScrollFlag = 0;
  2703.         }
  2704.         GetClip(utilRgn);
  2705.         ClipRect(&menuClipRect);
  2706.  
  2707.         if (oldItem != newItem) {
  2708.             if (oldItem >= 0) {
  2709.             mePtr = menuPtr->entries[oldItem];
  2710.             tkfont = mePtr->tkfont ? mePtr->tkfont : menuPtr->tkfont;
  2711.             Tk_GetFontMetrics(tkfont, &fontMetrics);
  2712.             TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable,
  2713.                 tkfont, &fontMetrics, 
  2714.                 menuRectPtr->left + mePtr->x,
  2715.                     globalsPtr->menuTop + mePtr->y,
  2716.                     (mePtr->entryFlags & ENTRY_LAST_COLUMN)
  2717.                     ? menuPtr->totalWidth - mePtr->x
  2718.                     : mePtr->width, mePtr->height, 0, 1);
  2719.         }
  2720.         if (newItem != -1) {
  2721.             int oldActiveItem = menuPtr->active;
  2722.             
  2723.             mePtr = menuPtr->entries[newItem];
  2724.             if (mePtr->state != tkDisabledUid) {
  2725.                 TkActivateMenuEntry(menuPtr, newItem);
  2726.             }
  2727.             tkfont = mePtr->tkfont ? mePtr->tkfont : menuPtr->tkfont;
  2728.             Tk_GetFontMetrics(tkfont, &fontMetrics);
  2729.             TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable,
  2730.                     tkfont, &fontMetrics, 
  2731.                     menuRectPtr->left + mePtr->x,
  2732.                     globalsPtr->menuTop + mePtr->y,
  2733.                     (mePtr->entryFlags & ENTRY_LAST_COLUMN)
  2734.                     ? menuPtr->totalWidth - mePtr->x
  2735.                     : mePtr->width, mePtr->height, 
  2736.                     0, 1);
  2737.         }
  2738.  
  2739.         tkUseMenuCascadeRgn = 1;
  2740.         MenuSelectEvent(menuPtr);
  2741.         Tcl_ServiceAll();
  2742.         tkUseMenuCascadeRgn = 0;
  2743.         if (mePtr->state != tkDisabledUid) {
  2744.             TkActivateMenuEntry(menuPtr, -1);
  2745.         }
  2746.             *whichItem = newItem + 1;
  2747.         }
  2748.         globalsPtr->menuDisable = ((*menu)->menuID << 16) | (newItem + 1);
  2749.         
  2750.         if (scrollDirection == UP_SCROLL) {
  2751.             scrollAmt = menuClipRect.bottom - hitPt.v;
  2752.             if (scrollAmt < menuRectPtr->bottom 
  2753.                 - globalsPtr->menuBottom) {
  2754.                 scrollAmt = menuRectPtr->bottom - globalsPtr->menuBottom;
  2755.             }
  2756.             if (!hasTopScroll && ((globalsPtr->menuTop + scrollAmt) < menuRectPtr->top)) {
  2757.                 SetRect(&updateRect, menuRectPtr->left,
  2758.                         globalsPtr->menuTop, menuRectPtr->right,
  2759.                         globalsPtr->menuTop + SICN_HEIGHT);
  2760.                 EraseRect(&updateRect);
  2761.                 DrawSICN(SICN_RESOURCE_NUMBER, UP_ARROW,
  2762.                         (Drawable) &macMDEFDrawable,
  2763.                         menuPtr->textGC, menuRectPtr->left
  2764.                         + menuPtr->entries[1]->indicatorSpace,
  2765.                         menuRectPtr->top);
  2766.                 menuClipRect.top += SICN_HEIGHT;
  2767.             }
  2768.         } else if (scrollDirection == DOWN_SCROLL) {
  2769.             scrollAmt = menuClipRect.top - hitPt.v;
  2770.             if (scrollAmt > menuRectPtr->top - globalsPtr->menuTop) {
  2771.                 scrollAmt = menuRectPtr->top - globalsPtr->menuTop;
  2772.             }
  2773.             if (!hasBottomScroll && ((globalsPtr->menuBottom + scrollAmt)
  2774.                 > menuRectPtr->bottom)) {
  2775.                 SetRect(&updateRect, menuRectPtr->left, 
  2776.                         globalsPtr->menuBottom - SICN_HEIGHT,
  2777.                         menuRectPtr->right, globalsPtr->menuBottom);
  2778.                 EraseRect(&updateRect);
  2779.                 DrawSICN(SICN_RESOURCE_NUMBER, DOWN_ARROW,
  2780.                         (Drawable) &macMDEFDrawable,
  2781.                         menuPtr->textGC, menuRectPtr->left
  2782.                         + menuPtr->entries[1]->indicatorSpace,
  2783.                         menuRectPtr->bottom - SICN_HEIGHT);
  2784.                 menuClipRect.bottom -= SICN_HEIGHT;
  2785.             }
  2786.         }
  2787.         if (scrollDirection != DONT_SCROLL) {
  2788.             RgnHandle updateRgn = NewRgn();
  2789.             ScrollRect(&menuClipRect, 0, scrollAmt, updateRgn);
  2790.             updateRect = (*updateRgn)->rgnBBox;
  2791.             DisposeRgn(updateRgn);
  2792.             globalsPtr->menuTop += scrollAmt;
  2793.             globalsPtr->menuBottom += scrollAmt;
  2794.             if (globalsPtr->menuTop == menuRectPtr->top) {
  2795.                 updateRect.top -= SICN_HEIGHT;
  2796.             }
  2797.             if (globalsPtr->menuBottom == menuRectPtr->bottom) {
  2798.                 updateRect.bottom += SICN_HEIGHT;
  2799.             }
  2800.         ClipRect(&updateRect);
  2801.         EraseRect(&updateRect);
  2802.             Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics);            
  2803.                 for (i = 0; i < menuPtr->numEntries; i++) {
  2804.                     mePtr = menuPtr->entries[i];
  2805.                     if (globalsPtr->menuTop + mePtr->y + mePtr->height
  2806.                         < updateRect.top) {
  2807.                         continue;
  2808.                     } else if (globalsPtr->menuTop + mePtr->y
  2809.                         > updateRect.bottom) {
  2810.                         continue;
  2811.                     }
  2812.                     if (mePtr->tkfont == NULL) {
  2813.                         fmPtr = &fontMetrics;
  2814.                         tkfont = menuPtr->tkfont;
  2815.                     } else {
  2816.                         tkfont = mePtr->tkfont;
  2817.                         Tk_GetFontMetrics(tkfont, &entryMetrics);
  2818.                         fmPtr = &entryMetrics;
  2819.                     }
  2820.                     TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable,
  2821.                         tkfont, fmPtr, menuRectPtr->left + mePtr->x, 
  2822.                         globalsPtr->menuTop + mePtr->y,
  2823.                         (mePtr->entryFlags & ENTRY_LAST_COLUMN) ?
  2824.                         menuPtr->totalWidth - mePtr->x : mePtr->width,
  2825.                         menuPtr->entries[i]->height, 0, 1);
  2826.                  }            
  2827.         }
  2828.  
  2829.         SetClip(utilRgn);
  2830.         SetEmptyRgn(utilRgn);
  2831.         RGBForeColor(&origForeColor);
  2832.         RGBBackColor(&origBackColor);
  2833.  
  2834.             /*
  2835.              * If the menu is a tearoff, and the mouse is outside the menu,
  2836.              * we need to draw the drag rectangle.
  2837.              *
  2838.              * In order for tearoffs to work properly, we need to set
  2839.              * the active member of the containing menubar.
  2840.              */
  2841.             
  2842.             menuRefPtr = TkFindMenuReferences(menuPtr->interp,
  2843.                     Tk_PathName(menuPtr->tkwin));
  2844.             if ((menuRefPtr != NULL) && (menuRefPtr->parentEntryPtr != NULL)) {
  2845.                 for (parentEntryPtr = menuRefPtr->parentEntryPtr;
  2846.                         strcmp(parentEntryPtr->name,
  2847.             Tk_PathName(menuPtr->tkwin)) == 0;
  2848.                 parentEntryPtr = parentEntryPtr->nextCascadePtr) {
  2849.                 }
  2850.                 if (parentEntryPtr != NULL) {
  2851.                     TkActivateMenuEntry(parentEntryPtr->menuPtr,
  2852.                 parentEntryPtr->index);
  2853.          }
  2854.             }
  2855.             
  2856.         if (menuPtr->tearOff) {
  2857.                scratchRect = *menuRectPtr;
  2858.         if (tearoffStruct.menuPtr == NULL) {
  2859.                    scratchRect.top -= 10;
  2860.                    scratchRect.bottom += 10;
  2861.                    scratchRect.left -= 10;
  2862.                    scratchRect.right += 10;
  2863.                }
  2864.  
  2865.             windowPart = FindWindow(hitPt, &whichWindow);
  2866.             if ((windowPart != inMenuBar) && (newItem == -1)
  2867.                 && (hitPt.v != 0) && (hitPt.h != 0)
  2868.                 && (!PtInRect(hitPt, &scratchRect))
  2869.                 && (!PtInRect(hitPt, &tearoffStruct.excludeRect))) {
  2870.                 long dummy;
  2871.                 
  2872.                 oldClipRgn = NewRgn();
  2873.                 GetClip(oldClipRgn);
  2874.                    GetForeColor(&origFgColor);
  2875.                    GetPenState(&origPenState);
  2876.                    GetForeColor(&fgColor);
  2877.                    GetBackColor(&bgColor);
  2878.                    GetGray(device, &bgColor, &fgColor);
  2879.                    RGBForeColor(&fgColor);
  2880.                    SetRect(&scratchRect, -32768, -32768, 32767, 32767);
  2881.                    ClipRect(&scratchRect);
  2882.                    
  2883.                     dragRect = *menuRectPtr;
  2884.             tearoffStruct.menuPtr = menuPtr;
  2885.  
  2886.                 PenMode(srcXor);
  2887.                    dragRect = *menuRectPtr;
  2888.                 OffsetRect(&dragRect, -dragRect.left, -dragRect.top);
  2889.                 OffsetRect(&dragRect, tearoffStruct.point.h,
  2890.                     tearoffStruct.point.v);
  2891.                    if ((dragRect.top != 0) && (dragRect.left != 0)) {
  2892.                     FrameRect(&dragRect);
  2893.                     Delay(1, &dummy);
  2894.                 FrameRect(&dragRect);
  2895.             }
  2896.             tearoffStruct.point = hitPt;
  2897.  
  2898.                 SetClip(oldClipRgn);
  2899.                 DisposeRgn(oldClipRgn);
  2900.                 RGBForeColor(&origFgColor);
  2901.                 SetPenState(&origPenState);    
  2902.         } else {
  2903.             tearoffStruct.menuPtr = NULL;
  2904.             tearoffStruct.point.h = tearoffStruct.point.v = 0;
  2905.         }
  2906.         } else {
  2907.             tearoffStruct.menuPtr = NULL;
  2908.             tearoffStruct.point.h = tearoffStruct.point.v = 0;
  2909.         }
  2910.         
  2911.         break;
  2912.     }
  2913.  
  2914.         case mPopUpMsg:
  2915.         
  2916.             /*
  2917.              * Note that for some oddball reason, h and v are reversed in the
  2918.              * point given to us by the MDEF.
  2919.              */
  2920.         
  2921.         oldItem = *whichItem;
  2922.         if (oldItem >= menuPtr->numEntries) {
  2923.             oldItem = -1;
  2924.         }
  2925.         GetWMgrPort(&windowMgrPort);
  2926.         maxMenuHeight = windowMgrPort->portRect.bottom
  2927.                 - windowMgrPort->portRect.top
  2928.                 - GetMBarHeight() - SCREEN_MARGIN;
  2929.         if (menuPtr->totalHeight > maxMenuHeight) {
  2930.             menuRectPtr->top = GetMBarHeight();
  2931.         } else {
  2932.             menuRectPtr->top = hitPt.h;
  2933.             if (oldItem >= 0) {
  2934.                 menuRectPtr->top -= menuPtr->entries[oldItem]->y;
  2935.             }
  2936.             if (menuRectPtr->top + menuPtr->totalHeight > maxMenuHeight) {
  2937.                 menuRectPtr->top -= maxMenuHeight - menuPtr->totalHeight;
  2938.             }
  2939.         }
  2940.             menuRectPtr->left = hitPt.v;
  2941.             menuRectPtr->right = menuRectPtr->left + menuPtr->totalWidth;
  2942.             menuRectPtr->bottom = menuRectPtr->top + 
  2943.                     ((maxMenuHeight < menuPtr->totalHeight) 
  2944.                     ? maxMenuHeight : menuPtr->totalHeight);
  2945.             if (menuRectPtr->top == GetMBarHeight()) {
  2946.                 *whichItem = hitPt.h;
  2947.             } else {
  2948.             *whichItem = menuRectPtr->top;
  2949.         }
  2950.             break;
  2951.     }
  2952. }
  2953.  
  2954. /*
  2955.  *----------------------------------------------------------------------
  2956.  *
  2957.  * TkMacHandleTearoffMenu() --
  2958.  *
  2959.  *    This routine sees if the MDEF has set a menu and a mouse position
  2960.  *    for tearing off and makes a tearoff menu if it has.
  2961.  *
  2962.  * Results:
  2963.  *    menuPtr->interp will have the result of the tearoff command.
  2964.  *
  2965.  * Side effects:
  2966.  *    A new tearoff menu is created if it is supposed to be.
  2967.  *
  2968.  *----------------------------------------------------------------------
  2969.  */
  2970.  
  2971. void
  2972. TkMacHandleTearoffMenu(void)
  2973. {
  2974.     if (tearoffStruct.menuPtr != NULL) {
  2975.         Tcl_DString tearoffCmdStr;
  2976.         char intString[20];
  2977.         short windowPart;
  2978.         WindowRef whichWindow;
  2979.         
  2980.         windowPart = FindWindow(tearoffStruct.point, &whichWindow);
  2981.         
  2982.         if (windowPart != inMenuBar) {
  2983.             Tcl_DStringInit(&tearoffCmdStr);
  2984.             Tcl_DStringAppendElement(&tearoffCmdStr, "tkTearOffMenu");
  2985.             Tcl_DStringAppendElement(&tearoffCmdStr, 
  2986.                 Tk_PathName(tearoffStruct.menuPtr->tkwin));
  2987.         sprintf(intString, "%d", tearoffStruct.point.h);
  2988.         Tcl_DStringAppendElement(&tearoffCmdStr, intString);
  2989.         sprintf(intString, "%d", tearoffStruct.point.v);
  2990.         Tcl_DStringAppendElement(&tearoffCmdStr, intString);
  2991.         Tcl_Eval(tearoffStruct.menuPtr->interp,
  2992.             Tcl_DStringValue(&tearoffCmdStr));
  2993.         Tcl_DStringFree(&tearoffCmdStr);
  2994.         tearoffStruct.menuPtr = NULL;
  2995.     }
  2996.     }
  2997. }
  2998.  
  2999. /*
  3000.  *--------------------------------------------------------------
  3001.  *
  3002.  * TkpInitializeMenuBindings --
  3003.  *
  3004.  *    For every interp, initializes the bindings for Windows
  3005.  *    menus. Does nothing on Mac or XWindows.
  3006.  *
  3007.  * Results:
  3008.  *    None.
  3009.  *
  3010.  * Side effects:
  3011.  *    C-level bindings are setup for the interp which will
  3012.  *    handle Alt-key sequences for menus without beeping
  3013.  *    or interfering with user-defined Alt-key bindings.
  3014.  *
  3015.  *--------------------------------------------------------------
  3016.  */
  3017.  
  3018. void
  3019. TkpInitializeMenuBindings(interp, bindingTable)
  3020.     Tcl_Interp *interp;            /* The interpreter to set. */
  3021.     Tk_BindingTable bindingTable;   /* The table to add to. */
  3022. {
  3023.     /*
  3024.      * Nothing to do.
  3025.      */
  3026. }
  3027.  
  3028. /*
  3029.  *--------------------------------------------------------------
  3030.  *
  3031.  * TkpComputeMenubarGeometry --
  3032.  *
  3033.  *    This procedure is invoked to recompute the size and
  3034.  *    layout of a menu that is a menubar clone.
  3035.  *
  3036.  * Results:
  3037.  *    None.
  3038.  *
  3039.  * Side effects:
  3040.  *    Fields of menu entries are changed to reflect their
  3041.  *    current positions, and the size of the menu window
  3042.  *    itself may be changed.
  3043.  *
  3044.  *--------------------------------------------------------------
  3045.  */
  3046.  
  3047. void
  3048. TkpComputeMenubarGeometry(menuPtr)
  3049.     TkMenu *menuPtr;        /* Structure describing menu. */
  3050. {
  3051.     TkpComputeStandardMenuGeometry(menuPtr);
  3052. }
  3053.  
  3054. /*
  3055.  *----------------------------------------------------------------------
  3056.  *
  3057.  * DrawTearoffEntry --
  3058.  *
  3059.  *    This procedure draws the background part of a menu.
  3060.  *
  3061.  * Results:
  3062.  *    None.
  3063.  *
  3064.  * Side effects:
  3065.  *    Commands are output to X to display the menu in its
  3066.  *    current mode.
  3067.  *
  3068.  *----------------------------------------------------------------------
  3069.  */
  3070.  
  3071. void
  3072. DrawTearoffEntry(
  3073.     TkMenu *menuPtr,            /* The menu we are drawing */
  3074.     TkMenuEntry *mePtr,            /* The entry we are drawing */
  3075.     Drawable d,                /* The drawable we are drawing into */
  3076.     GC gc,                /* The gc we are drawing with */
  3077.     Tk_Font tkfont,            /* The font we are drawing with */
  3078.     CONST Tk_FontMetrics *fmPtr,    /* The metrics we are drawing with */
  3079.     int x,                /* Left edge of entry. */
  3080.     int y,                /* Top edge of entry. */
  3081.     int width,                /* Width of entry. */
  3082.     int height)                /* Height of entry. */
  3083. {
  3084.     XPoint points[2];
  3085.     int margin, segmentWidth, maxX;
  3086.  
  3087.     if ((menuPtr->menuType != MASTER_MENU) || (GetResource('MDEF', 591) != NULL)) {
  3088.     return;
  3089.     }
  3090.     
  3091.     margin = (fmPtr->ascent + fmPtr->descent)/2;
  3092.     points[0].x = x;
  3093.     points[0].y = y + height/2;
  3094.     points[1].y = points[0].y;
  3095.     segmentWidth = 6;
  3096.     maxX  = width - 1;
  3097.  
  3098.     while (points[0].x < maxX) {
  3099.     points[1].x = points[0].x + segmentWidth;
  3100.     if (points[1].x > maxX) {
  3101.         points[1].x = maxX;
  3102.     }
  3103.     Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1,
  3104.         TK_RELIEF_RAISED);
  3105.     points[0].x += 2*segmentWidth;
  3106.     }
  3107. }
  3108.  
  3109. /*
  3110.  *----------------------------------------------------------------------
  3111.  *
  3112.  * TkMacSetHelpMenuItemCount --
  3113.  *
  3114.  *    Has to be called after the first call to InsertMenu. Sets
  3115.  *    up the global variable for the number of items in the
  3116.  *    unmodified help menu.
  3117.  *
  3118.  * Results:
  3119.  *    None.
  3120.  *
  3121.  * Side effects:
  3122.  *    Sets the global helpItemCount.
  3123.  *
  3124.  *----------------------------------------------------------------------
  3125.  */
  3126.  
  3127. void 
  3128. TkMacSetHelpMenuItemCount()
  3129. {
  3130.     MenuHandle helpMenuHandle;
  3131.     
  3132.     if ((HMGetHelpMenuHandle(&helpMenuHandle) != noErr) 
  3133.             || (helpMenuHandle == NULL)) {
  3134.         helpItemCount = -1;
  3135.     } else {
  3136.         helpItemCount = CountMItems(helpMenuHandle);
  3137.         DeleteMenuItem(helpMenuHandle, helpItemCount);
  3138.     }
  3139. }
  3140.  
  3141. /*
  3142.  *----------------------------------------------------------------------
  3143.  *
  3144.  * TkMacMenuClick --
  3145.  *
  3146.  *    Prepares a menubar for MenuSelect or MenuKey.
  3147.  *
  3148.  * Results:
  3149.  *    None.
  3150.  *
  3151.  * Side effects:
  3152.  *    Any pending configurations of the menubar are completed.
  3153.  *
  3154.  *----------------------------------------------------------------------
  3155.  */
  3156.  
  3157. void
  3158. TkMacMenuClick()
  3159. {
  3160.     TkMenu *menuPtr;
  3161.     TkMenuReferences *menuRefPtr;
  3162.     
  3163.     if ((currentMenuBarInterp != NULL) && (currentMenuBarName != NULL)) {
  3164.         menuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
  3165.             currentMenuBarName);
  3166.         for (menuPtr = menuRefPtr->menuPtr->masterMenuPtr;
  3167.             menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) {
  3168.             if (menuPtr->menuType == MENUBAR) {
  3169.                 CompleteIdlers(menuPtr);
  3170.                 break;
  3171.             }
  3172.         }
  3173.     }
  3174.     
  3175.     if (menuBarFlags & MENUBAR_REDRAW_PENDING) {
  3176.         Tcl_CancelIdleCall(DrawMenuBarWhenIdle, (ClientData *) NULL);
  3177.         DrawMenuBarWhenIdle((ClientData *) NULL);
  3178.     }
  3179. }
  3180.  
  3181. /*
  3182.  *----------------------------------------------------------------------
  3183.  *
  3184.  * TkpDrawMenuEntry --
  3185.  *
  3186.  *    Draws the given menu entry at the given coordinates with the
  3187.  *    given attributes.
  3188.  *
  3189.  * Results:
  3190.  *    None.
  3191.  *
  3192.  * Side effects:
  3193.  *    X Server commands are executed to display the menu entry.
  3194.  *
  3195.  *----------------------------------------------------------------------
  3196.  */
  3197.  
  3198. void
  3199. TkpDrawMenuEntry(
  3200.     TkMenuEntry *mePtr,            /* The entry to draw */
  3201.     Drawable d,                /* What to draw into */
  3202.     Tk_Font tkfont,            /* Precalculated font for menu */
  3203.     CONST Tk_FontMetrics *menuMetricsPtr,
  3204.                     /* Precalculated metrics for menu */
  3205.     int x,                /* X-coordinate of topleft of entry */
  3206.     int y,                /* Y-coordinate of topleft of entry */
  3207.     int width,                /* Width of the entry rectangle */
  3208.     int height,                /* Height of the current rectangle */
  3209.     int strictMotif,            /* Boolean flag */
  3210.     int drawArrow)            /* Whether or not to draw the cascade
  3211.                      * arrow for cascade items. Only applies
  3212.                      * to Windows. */
  3213. {
  3214.     GC gc, indicatorGC;
  3215.     TkMenu *menuPtr = mePtr->menuPtr;
  3216.     Tk_3DBorder bgBorder, activeBorder;
  3217.     CONST Tk_FontMetrics *fmPtr;
  3218.     Tk_FontMetrics entryMetrics;
  3219.     int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0;
  3220.     int adjustedY = y + padY;
  3221.     int adjustedHeight = height - 2 * padY;
  3222.  
  3223.     /*
  3224.      * Choose the gc for drawing the foreground part of the entry.
  3225.      */
  3226.  
  3227.     if ((mePtr->state == tkActiveUid)
  3228.         && !strictMotif) {
  3229.     gc = mePtr->activeGC;
  3230.     if (gc == NULL) {
  3231.         gc = menuPtr->activeGC;
  3232.     }
  3233.     } else {
  3234.         TkMenuEntry *cascadeEntryPtr;
  3235.         int parentDisabled = 0;
  3236.         
  3237.         for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
  3238.             cascadeEntryPtr != NULL;
  3239.             cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
  3240.             if (strcmp(cascadeEntryPtr->name, 
  3241.                     Tk_PathName(menuPtr->tkwin)) == 0) {
  3242.                 if (cascadeEntryPtr->state == tkDisabledUid) {
  3243.                     parentDisabled = 1;
  3244.                 }
  3245.                 break;
  3246.             }
  3247.         }
  3248.  
  3249.     if (((parentDisabled || (mePtr->state == tkDisabledUid)))
  3250.         && (menuPtr->disabledFg != NULL)) {
  3251.         gc = mePtr->disabledGC;
  3252.         if (gc == NULL) {
  3253.         gc = menuPtr->disabledGC;
  3254.         }
  3255.     } else {
  3256.         gc = mePtr->textGC;
  3257.         if (gc == NULL) {
  3258.         gc = menuPtr->textGC;
  3259.         }
  3260.     }
  3261.     }
  3262.     indicatorGC = mePtr->indicatorGC;
  3263.     if (indicatorGC == NULL) {
  3264.     indicatorGC = menuPtr->indicatorGC;
  3265.     }
  3266.         
  3267.     bgBorder = mePtr->border;
  3268.     if (bgBorder == NULL) {
  3269.     bgBorder = menuPtr->border;
  3270.     }
  3271.     if (strictMotif) {
  3272.     activeBorder = bgBorder;
  3273.     } else {
  3274.     activeBorder = mePtr->activeBorder;
  3275.     if (activeBorder == NULL) {
  3276.         activeBorder = menuPtr->activeBorder;
  3277.     }
  3278.     }
  3279.  
  3280.     if (mePtr->tkfont == NULL) {
  3281.     fmPtr = menuMetricsPtr;
  3282.     } else {
  3283.     tkfont = mePtr->tkfont;
  3284.     Tk_GetFontMetrics(tkfont, &entryMetrics);
  3285.     fmPtr = &entryMetrics;
  3286.     }
  3287.  
  3288.     /*
  3289.      * Need to draw the entire background, including padding. On Unix,
  3290.      * for menubars, we have to draw the rest of the entry taking
  3291.      * into account the padding.
  3292.      */
  3293.     
  3294.     DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, 
  3295.         bgBorder, x, y, width, height);
  3296.     
  3297.     if (mePtr->type == SEPARATOR_ENTRY) {
  3298.     DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, 
  3299.         fmPtr, x, adjustedY, width, adjustedHeight);
  3300.     } else if (mePtr->type == TEAROFF_ENTRY) {
  3301.     DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
  3302.         width, adjustedHeight);
  3303.     } else {
  3304.     DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, 
  3305.         adjustedY, width, adjustedHeight);
  3306.     DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
  3307.         activeBorder, x, adjustedY, width, adjustedHeight, drawArrow);
  3308.     if (!mePtr->hideMargin) {
  3309.         DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont,
  3310.             fmPtr, x, adjustedY, width, adjustedHeight);
  3311.     }
  3312.     }
  3313. }
  3314.  
  3315. /*
  3316.  *--------------------------------------------------------------
  3317.  *
  3318.  * TkpComputeStandardMenuGeometry --
  3319.  *
  3320.  *    This procedure is invoked to recompute the size and
  3321.  *    layout of a menu that is not a menubar clone.
  3322.  *
  3323.  * Results:
  3324.  *    None.
  3325.  *
  3326.  * Side effects:
  3327.  *    Fields of menu entries are changed to reflect their
  3328.  *    current positions, and the size of the menu window
  3329.  *    itself may be changed.
  3330.  *
  3331.  *--------------------------------------------------------------
  3332.  */
  3333.  
  3334. void
  3335. TkpComputeStandardMenuGeometry(
  3336.     TkMenu *menuPtr)        /* Structure describing menu. */
  3337. {
  3338.     Tk_Font tkfont;
  3339.     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
  3340.     int x, y, height, modifierWidth, labelWidth, indicatorSpace;
  3341.     int windowWidth, windowHeight, accelWidth, maxAccelTextWidth;
  3342.     int i, j, lastColumnBreak, maxModifierWidth, maxWidth, nonAccelMargin;
  3343.     int maxNonAccelMargin, maxEntryWithAccelWidth, maxEntryWithoutAccelWidth;
  3344.     int entryWidth, maxIndicatorSpace;
  3345.     TkMenuEntry *mePtr, *columnEntryPtr;
  3346.     EntryGeometry *geometryPtr;
  3347.     
  3348.     if (menuPtr->tkwin == NULL) {
  3349.     return;
  3350.     }
  3351.  
  3352.     x = y = menuPtr->borderWidth;
  3353.     indicatorSpace = labelWidth = accelWidth = maxAccelTextWidth = 0;
  3354.     windowHeight = windowWidth = maxWidth = lastColumnBreak = 0;
  3355.     maxModifierWidth = nonAccelMargin = maxNonAccelMargin = 0;
  3356.     maxEntryWithAccelWidth = maxEntryWithoutAccelWidth = 0;
  3357.     maxIndicatorSpace = 0;
  3358.  
  3359.     /*
  3360.      * On the Mac especially, getting font metrics can be quite slow,
  3361.      * so we want to do it intelligently. We are going to precalculate
  3362.      * them and pass them down to all of the measuring and drawing
  3363.      * routines. We will measure the font metrics of the menu once.
  3364.      * If an entry does not have its own font set, then we give
  3365.      * the geometry/drawing routines the menu's font and metrics.
  3366.      * If an entry has its own font, we will measure that font and
  3367.      * give all of the geometry/drawing the entry's font and metrics.
  3368.      */
  3369.  
  3370.     Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics);
  3371.  
  3372.     for (i = 0; i < menuPtr->numEntries; i++) {
  3373.         mePtr = menuPtr->entries[i];
  3374.         tkfont = mePtr->tkfont;
  3375.         if (tkfont == NULL) {
  3376.             tkfont = menuPtr->tkfont;
  3377.             fmPtr = &menuMetrics;
  3378.         } else {
  3379.             Tk_GetFontMetrics(tkfont, &entryMetrics);
  3380.             fmPtr = &entryMetrics;
  3381.         }
  3382.         
  3383.     if ((i > 0) && mePtr->columnBreak) {
  3384.         if (maxIndicatorSpace != 0) {
  3385.         maxIndicatorSpace += 2;
  3386.         }
  3387.         for (j = lastColumnBreak; j < i; j++) {
  3388.             columnEntryPtr = menuPtr->entries[j];
  3389.             geometryPtr =
  3390.                 (EntryGeometry *) columnEntryPtr->platformEntryData;
  3391.             
  3392.             columnEntryPtr->indicatorSpace = maxIndicatorSpace;
  3393.         columnEntryPtr->width = maxIndicatorSpace + maxWidth 
  3394.             + 2 * menuPtr->activeBorderWidth;
  3395.         geometryPtr->accelTextWidth = maxAccelTextWidth;
  3396.         geometryPtr->modifierWidth = maxModifierWidth;
  3397.         columnEntryPtr->x = x;
  3398.         columnEntryPtr->entryFlags &= ~ENTRY_LAST_COLUMN;
  3399.         if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) {
  3400.             geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth
  3401.                     - maxEntryWithAccelWidth;
  3402.             if (geometryPtr->nonAccelMargin > maxNonAccelMargin) {
  3403.                 geometryPtr->nonAccelMargin = maxNonAccelMargin;
  3404.             }
  3405.         } else {
  3406.             geometryPtr->nonAccelMargin = 0;
  3407.         }        
  3408.         }
  3409.         x += maxIndicatorSpace + maxWidth + 2 * menuPtr->borderWidth;
  3410.         windowWidth = x;
  3411.         maxWidth = maxIndicatorSpace = maxAccelTextWidth = 0;
  3412.         maxModifierWidth = maxNonAccelMargin = maxEntryWithAccelWidth = 0;
  3413.         maxEntryWithoutAccelWidth = 0;
  3414.         lastColumnBreak = i;
  3415.         y = menuPtr->borderWidth;
  3416.     }
  3417.  
  3418.     if (mePtr->type == SEPARATOR_ENTRY) {
  3419.         GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont,
  3420.                 fmPtr, &entryWidth, &height);
  3421.         mePtr->height = height;
  3422.     } else if (mePtr->type == TEAROFF_ENTRY) {
  3423.         GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, 
  3424.                 fmPtr, &entryWidth, &height);
  3425.         mePtr->height = height;
  3426.     } else {
  3427.         
  3428.         /*
  3429.          * For each entry, compute the height required by that
  3430.          * particular entry, plus three widths:  the width of the
  3431.          * label, the width to allow for an indicator to be displayed
  3432.          * to the left of the label (if any), and the width of the
  3433.          * accelerator to be displayed to the right of the label
  3434.          * (if any).  These sizes depend, of course, on the type
  3435.          * of the entry.
  3436.          */
  3437.         
  3438.         GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &labelWidth,
  3439.                 &height);
  3440.         mePtr->height = height;
  3441.     
  3442.         if (mePtr->type == CASCADE_ENTRY) {
  3443.             GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr,
  3444.                 &modifierWidth, &accelWidth, &height);
  3445.             nonAccelMargin = 0;
  3446.         } else if (mePtr->accelLength == 0) {
  3447.             nonAccelMargin = mePtr->hideMargin ? 0 
  3448.                 : Tk_TextWidth(tkfont, "m", 1);
  3449.             accelWidth = modifierWidth = 0;
  3450.         } else {
  3451.             labelWidth += Tk_TextWidth(tkfont, "m", 1);
  3452.             GetMenuAccelGeometry(menuPtr, mePtr, tkfont,
  3453.                 fmPtr, &modifierWidth, &accelWidth, &height);
  3454.             if (height > mePtr->height) {
  3455.                 mePtr->height = height;
  3456.             }
  3457.             nonAccelMargin = 0;
  3458.         }
  3459.  
  3460.         if (!(mePtr->hideMargin)) {
  3461.             GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, 
  3462.                     fmPtr, &indicatorSpace, &height);
  3463.             if (height > mePtr->height) {
  3464.                 mePtr->height = height;
  3465.             }
  3466.         } else {
  3467.             indicatorSpace = 0;
  3468.         }
  3469.  
  3470.         if (nonAccelMargin > maxNonAccelMargin) {
  3471.             maxNonAccelMargin = nonAccelMargin;
  3472.         }
  3473.         if (accelWidth > maxAccelTextWidth) {
  3474.             maxAccelTextWidth = accelWidth;
  3475.         }
  3476.         if (modifierWidth > maxModifierWidth) {
  3477.             maxModifierWidth = modifierWidth;
  3478.         }
  3479.         if (indicatorSpace > maxIndicatorSpace) {
  3480.             maxIndicatorSpace = indicatorSpace;
  3481.         }
  3482.  
  3483.         entryWidth = labelWidth + modifierWidth + accelWidth
  3484.             + nonAccelMargin;
  3485.  
  3486.         if (entryWidth > maxWidth) {
  3487.             maxWidth = entryWidth;
  3488.         }
  3489.         
  3490.         if (mePtr->accelLength > 0) {
  3491.             if (entryWidth > maxEntryWithAccelWidth) {
  3492.                 maxEntryWithAccelWidth = entryWidth;
  3493.             }
  3494.         } else {
  3495.             if (entryWidth > maxEntryWithoutAccelWidth) {
  3496.                 maxEntryWithoutAccelWidth = entryWidth;
  3497.             }
  3498.         }
  3499.         
  3500.         mePtr->height += 2 * menuPtr->activeBorderWidth;
  3501.         }
  3502.         mePtr->y = y;
  3503.     y += menuPtr->entries[i]->height + menuPtr->borderWidth;
  3504.     if (y > windowHeight) {
  3505.         windowHeight = y;
  3506.     }
  3507.     }
  3508.  
  3509.     for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
  3510.         columnEntryPtr = menuPtr->entries[j];
  3511.         geometryPtr = (EntryGeometry *) columnEntryPtr->platformEntryData;
  3512.         
  3513.         columnEntryPtr->indicatorSpace = maxIndicatorSpace;
  3514.     columnEntryPtr->width = maxIndicatorSpace + maxWidth 
  3515.         + 2 * menuPtr->activeBorderWidth;
  3516.     geometryPtr->accelTextWidth = maxAccelTextWidth;
  3517.     geometryPtr->modifierWidth = maxModifierWidth;
  3518.     columnEntryPtr->x = x;
  3519.     columnEntryPtr->entryFlags |= ENTRY_LAST_COLUMN;
  3520.     if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) {
  3521.         geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth
  3522.                 - maxEntryWithAccelWidth;
  3523.         if (geometryPtr->nonAccelMargin > maxNonAccelMargin) {
  3524.             geometryPtr->nonAccelMargin = maxNonAccelMargin;
  3525.         }
  3526.     } else {
  3527.         geometryPtr->nonAccelMargin = 0;
  3528.     }        
  3529.     }
  3530.     windowWidth = x + maxIndicatorSpace + maxWidth
  3531.         + 2 * menuPtr->activeBorderWidth + menuPtr->borderWidth;
  3532.     windowHeight += menuPtr->borderWidth;
  3533.     
  3534.     /*
  3535.      * The X server doesn't like zero dimensions, so round up to at least
  3536.      * 1 (a zero-sized menu should never really occur, anyway).
  3537.      */
  3538.  
  3539.     if (windowWidth <= 0) {
  3540.     windowWidth = 1;
  3541.     }
  3542.     if (windowHeight <= 0) {
  3543.     windowHeight = 1;
  3544.     }
  3545.     menuPtr->totalWidth = windowWidth;
  3546.     menuPtr->totalHeight = windowHeight;
  3547. }
  3548.  
  3549. /*
  3550.  *----------------------------------------------------------------------
  3551.  *
  3552.  * DrawMenuEntryLabel --
  3553.  *
  3554.  *    This procedure draws the label part of a menu.
  3555.  *
  3556.  * Results:
  3557.  *    None.
  3558.  *
  3559.  * Side effects:
  3560.  *    Commands are output to X to display the menu in its
  3561.  *    current mode.
  3562.  *
  3563.  *----------------------------------------------------------------------
  3564.  */
  3565.  
  3566. static void
  3567. DrawMenuEntryLabel(
  3568.     TkMenu *menuPtr,            /* The menu we are drawing */
  3569.     TkMenuEntry *mePtr,            /* The entry we are drawing */
  3570.     Drawable d,                /* What we are drawing into */
  3571.     GC gc,                /* The gc we are drawing into */
  3572.     Tk_Font tkfont,            /* The precalculated font */
  3573.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
  3574.     int x,                /* left edge */
  3575.     int y,                /* right edge */
  3576.     int width,                /* width of entry */
  3577.     int height)                /* height of entry */
  3578. {
  3579.     int baseline;
  3580.     int indicatorSpace =  mePtr->indicatorSpace;
  3581.     int leftEdge = x + indicatorSpace;
  3582.     int imageHeight, imageWidth;
  3583.     
  3584.     /*
  3585.      * Draw label or bitmap or image for entry.
  3586.      */
  3587.  
  3588.     baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
  3589.     if (mePtr->image != NULL) {
  3590.         Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
  3591.         if ((mePtr->selectImage != NULL)
  3592.             && (mePtr->entryFlags & ENTRY_SELECTED)) {
  3593.         Tk_RedrawImage(mePtr->selectImage, 0, 0,
  3594.             imageWidth, imageHeight, d, leftEdge,
  3595.                 (int) (y + (mePtr->height - imageHeight)/2));
  3596.         } else {
  3597.         Tk_RedrawImage(mePtr->image, 0, 0, imageWidth,
  3598.             imageHeight, d, leftEdge,
  3599.             (int) (y + (mePtr->height - imageHeight)/2));
  3600.         }
  3601.     } else if (mePtr->bitmap != None) {
  3602.         int width, height;
  3603.  
  3604.         Tk_SizeOfBitmap(menuPtr->display,
  3605.             mePtr->bitmap, &width, &height);
  3606.         XCopyPlane(menuPtr->display,
  3607.             mePtr->bitmap, d,
  3608.             gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge,
  3609.             (int) (y + (mePtr->height - height)/2), 1);
  3610.     } else {
  3611.         if (mePtr->labelLength > 0) {
  3612.             Str255 itemText;
  3613.             
  3614.             GetEntryText(mePtr, itemText);
  3615.         Tk_DrawChars(menuPtr->display, d, gc,
  3616.             tkfont, (char *) itemText + 1, itemText[0],
  3617.             leftEdge, baseline);
  3618. /*        TkpDrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y,
  3619.             width, height);*/
  3620.         }
  3621.     }
  3622.  
  3623.     if (mePtr->state == tkDisabledUid) {
  3624.     if (menuPtr->disabledFg == NULL) {
  3625.         XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y,
  3626.             (unsigned) width, (unsigned) height);
  3627.     } else if ((mePtr->image != NULL) 
  3628.         && (menuPtr->disabledImageGC != None)) {
  3629.         XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
  3630.             leftEdge,
  3631.             (int) (y + (mePtr->height - imageHeight)/2),
  3632.             (unsigned) imageWidth, (unsigned) imageHeight);
  3633.     }
  3634.     }
  3635. }
  3636.  
  3637. /*
  3638.  *----------------------------------------------------------------------
  3639.  *
  3640.  * DrawMenuEntryBackground --
  3641.  *
  3642.  *    This procedure draws the background part of a menu.
  3643.  *
  3644.  * Results:
  3645.  *    None.
  3646.  *
  3647.  * Side effects:
  3648.  *    Commands are output to X to display the menu in its
  3649.  *    current mode.
  3650.  *
  3651.  *----------------------------------------------------------------------
  3652.  */
  3653.  
  3654. static void
  3655. DrawMenuEntryBackground(
  3656.     TkMenu *menuPtr,            /* The menu we are drawing. */
  3657.     TkMenuEntry *mePtr,            /* The entry we are drawing. */
  3658.     Drawable d,                /* What we are drawing into */
  3659.     Tk_3DBorder activeBorder,        /* Border for active items */
  3660.     Tk_3DBorder bgBorder,        /* Border for the background */
  3661.     int x,                /* left edge */
  3662.     int y,                /* top edge */
  3663.     int width,                /* width of rectangle to draw */
  3664.     int height)                /* height of rectangle to draw */
  3665. {
  3666.     if (mePtr->state == tkActiveUid) {
  3667.     bgBorder = activeBorder;
  3668.     }
  3669.     Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder,
  3670.             x, y, width, height, 0, TK_RELIEF_FLAT);
  3671. }
  3672.  
  3673. /*
  3674.  *----------------------------------------------------------------------
  3675.  *
  3676.  * GetMenuLabelGeometry --
  3677.  *
  3678.  *    Figures out the size of the label portion of a menu item.
  3679.  *
  3680.  * Results:
  3681.  *    widthPtr and heightPtr are filled in with the correct geometry
  3682.  *    information.
  3683.  *
  3684.  * Side effects:
  3685.  *    None.
  3686.  *
  3687.  *----------------------------------------------------------------------
  3688.  */
  3689.  
  3690. static void
  3691. GetMenuLabelGeometry(
  3692.     TkMenuEntry *mePtr,            /* The entry we are computing */
  3693.     Tk_Font tkfont,            /* The precalculated font */
  3694.     CONST Tk_FontMetrics *fmPtr,    /* The precalculated metrics */
  3695.     int *widthPtr,            /* The resulting width of the label
  3696.                      * portion */
  3697.     int *heightPtr)            /* The resulting height of the label
  3698.                      * portion */
  3699. {
  3700.     TkMenu *menuPtr = mePtr->menuPtr;
  3701.  
  3702.     if (mePtr->image != NULL) {
  3703.         Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
  3704.     } else if (mePtr->bitmap != (Pixmap) NULL) {
  3705.         Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, widthPtr, heightPtr);
  3706.     } else {
  3707.         *heightPtr = fmPtr->linespace;
  3708.         
  3709.         if (mePtr->label != NULL) {
  3710.             Str255 itemText;
  3711.             
  3712.             GetEntryText(mePtr, itemText);
  3713.             *widthPtr = Tk_TextWidth(tkfont, (char *) itemText + 1,
  3714.             itemText[0]);
  3715.         } else {
  3716.             *widthPtr = 0;
  3717.         }
  3718.     }
  3719.     *heightPtr += 1;
  3720. }
  3721.  
  3722. /*
  3723.  *----------------------------------------------------------------------
  3724.  *
  3725.  * MenuSelectEvent --
  3726.  *
  3727.  *    Generates a "MenuSelect" virtual event. This can be used to
  3728.  *    do context-sensitive menu help.
  3729.  *
  3730.  * Results:
  3731.  *    None.
  3732.  *
  3733.  * Side effects:
  3734.  *    Places a virtual event on the event queue.
  3735.  *
  3736.  *----------------------------------------------------------------------
  3737.  */
  3738.  
  3739. static void
  3740. MenuSelectEvent(
  3741.     TkMenu *menuPtr)        /* the menu we have selected. */
  3742. {
  3743.     XVirtualEvent event;
  3744.     Point where;
  3745.    
  3746.     event.type = VirtualEvent;
  3747.     event.serial = menuPtr->display->request;
  3748.     event.send_event = false;
  3749.     event.display = menuPtr->display;
  3750.     Tk_MakeWindowExist(menuPtr->tkwin);
  3751.     event.event = Tk_WindowId(menuPtr->tkwin);
  3752.     event.root = XRootWindow(menuPtr->display, 0);
  3753.     event.subwindow = None;
  3754.     event.time = TkpGetMS();
  3755.     
  3756.     GetMouse(&where);
  3757.     event.x_root = where.h;
  3758.     event.y_root = where.v;
  3759.     event.state = TkMacButtonKeyState();
  3760.     event.same_screen = true;
  3761.     event.name = Tk_GetUid("MenuSelect");
  3762.     Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
  3763. }
  3764.  
  3765. /*
  3766.  *----------------------------------------------------------------------
  3767.  *
  3768.  * RecursivelyClearActiveMenu --
  3769.  *
  3770.  *    Recursively clears the active entry in the menu's cascade hierarchy.
  3771.  *
  3772.  * Results:
  3773.  *    None.
  3774.  *
  3775.  * Side effects:
  3776.  *    Generates <<MenuSelect>> virtual events.
  3777.  *
  3778.  *----------------------------------------------------------------------
  3779.  */
  3780.  
  3781. void
  3782. RecursivelyClearActiveMenu(
  3783.     TkMenu *menuPtr)        /* The menu to reset. */
  3784. {
  3785.     int i;
  3786.     TkMenuEntry *mePtr;
  3787.     
  3788.     TkActivateMenuEntry(menuPtr, -1);
  3789.     MenuSelectEvent(menuPtr);
  3790.     for (i = 0; i < menuPtr->numEntries; i++) {
  3791.         mePtr = menuPtr->entries[i];
  3792.         if (mePtr->type == CASCADE_ENTRY) {
  3793.             if ((mePtr->childMenuRefPtr != NULL)
  3794.                     && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
  3795.                 RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr);
  3796.             }
  3797.         }
  3798.     }
  3799. }
  3800.  
  3801. /*
  3802.  *----------------------------------------------------------------------
  3803.  *
  3804.  * InvalidateMDEFRgns --
  3805.  *
  3806.  *    Invalidates the regions covered by menus that did redrawing and
  3807.  *    might be damaged.
  3808.  *
  3809.  * Results:
  3810.  *    None.
  3811.  *
  3812.  * Side effects:
  3813.  *    Generates Mac update events for affected windows.
  3814.  *
  3815.  *----------------------------------------------------------------------
  3816.  */
  3817.  
  3818. void
  3819. InvalidateMDEFRgns(void) {
  3820.     GDHandle saveDevice;
  3821.     GWorldPtr saveWorld, destPort;
  3822.     Point scratch;
  3823.     MacDrawable *macDraw;
  3824.     TkMacWindowList *listPtr;
  3825.     
  3826.     if (totalMenuRgn == NULL) {
  3827.         return;
  3828.     }
  3829.     
  3830.     GetGWorld(&saveWorld, &saveDevice);
  3831.     for (listPtr = tkMacWindowListPtr ; listPtr != NULL; 
  3832.             listPtr = listPtr->nextPtr) {
  3833.         macDraw = (MacDrawable *) Tk_WindowId(listPtr->winPtr);
  3834.         if (macDraw->flags & TK_DRAWN_UNDER_MENU) {
  3835.             destPort = TkMacGetDrawablePort(Tk_WindowId(listPtr->winPtr));
  3836.             SetGWorld(destPort, NULL);
  3837.             scratch.h = scratch.v = 0;
  3838.             GlobalToLocal(&scratch);
  3839.             OffsetRgn(totalMenuRgn, scratch.v, scratch.h);
  3840.             InvalRgn(totalMenuRgn);
  3841.             OffsetRgn(totalMenuRgn, -scratch.v, -scratch.h);
  3842.             macDraw->flags &= ~TK_DRAWN_UNDER_MENU;
  3843.         }
  3844.     }
  3845.     
  3846.     SetGWorld(saveWorld, saveDevice);
  3847.     SetEmptyRgn(totalMenuRgn);
  3848. }
  3849.  
  3850. /*
  3851.  *----------------------------------------------------------------------
  3852.  *
  3853.  * TkMacClearMenubarActive --
  3854.  *
  3855.  *    Recursively clears the active entry in the current menubar hierarchy.
  3856.  *
  3857.  * Results:
  3858.  *    None.
  3859.  *
  3860.  * Side effects:
  3861.  *    Generates <<MenuSelect>> virtual events.
  3862.  *
  3863.  *----------------------------------------------------------------------
  3864.  */
  3865.  
  3866. void
  3867. TkMacClearMenubarActive(void) {
  3868.     TkMenuReferences *menuBarRefPtr;
  3869.     
  3870.     if (currentMenuBarName != NULL) {
  3871.         menuBarRefPtr = TkFindMenuReferences(currentMenuBarInterp,
  3872.             currentMenuBarName);
  3873.         if ((menuBarRefPtr != NULL) && (menuBarRefPtr->menuPtr != NULL)) {
  3874.             TkMenu *menuPtr;
  3875.             
  3876.             for (menuPtr = menuBarRefPtr->menuPtr->masterMenuPtr; menuPtr != NULL;
  3877.                     menuPtr = menuPtr->nextInstancePtr) {
  3878.                 if (menuPtr->menuType == MENUBAR) {
  3879.                     RecursivelyClearActiveMenu(menuPtr);
  3880.                 }
  3881.             }
  3882.         }
  3883.     }
  3884.     InvalidateMDEFRgns();
  3885. }
  3886.  
  3887. /*
  3888.  *----------------------------------------------------------------------
  3889.  *
  3890.  * TkpMenuNotifyToplevelCreate --
  3891.  *
  3892.  *    This routine reconfigures the menu and the clones indicated by
  3893.  *    menuName becuase a toplevel has been created and any system
  3894.  *    menus need to be created. Only applicable to Windows.
  3895.  *
  3896.  * Results:
  3897.  *    None.
  3898.  *
  3899.  * Side effects:
  3900.  *    An idle handler is set up to do the reconfiguration.
  3901.  *
  3902.  *----------------------------------------------------------------------
  3903.  */
  3904.  
  3905. void
  3906. TkpMenuNotifyToplevelCreate(
  3907.     Tcl_Interp *interp,            /* The interp the menu lives in. */
  3908.     char *menuName)            /* The name of the menu to 
  3909.                      * reconfigure. */
  3910. {
  3911.     /*
  3912.      * Nothing to do.
  3913.      */
  3914. }
  3915.  
  3916. /*
  3917.  *----------------------------------------------------------------------
  3918.  *
  3919.  * TkpMenuInit --
  3920.  *
  3921.  *    Initializes Mac-specific menu data.
  3922.  *
  3923.  * Results:
  3924.  *    None.
  3925.  *
  3926.  * Side effects:
  3927.  *    Allcates a hash table.
  3928.  *
  3929.  *----------------------------------------------------------------------
  3930.  */
  3931.  
  3932. void
  3933. TkpMenuInit(void)
  3934. {
  3935.     /* 
  3936.      * We have to set up the MDEF. This is pretty slimy. The real MDEF
  3937.      * resource is 68K code. All this code does is call another procedure.
  3938.      * When the application in launched, a dummy value for the procedure
  3939.      * is compiled into the MDEF. We are going to replace that dummy
  3940.      * value with a routine descriptor. When the routine descriptor
  3941.      * is invoked, the globals and everything will be setup, and we
  3942.      * can do what we need. This will not work from 68K or CFM 68k
  3943.      * currently, so we will conditional compile this until we
  3944.      * figure it out. 
  3945.      */
  3946.     
  3947. #ifdef GENERATINGCFM
  3948.     Handle MDEFHandle = GetResource('MDEF', 591);
  3949.     Handle SICNHandle = GetResource('SICN', SICN_RESOURCE_NUMBER);
  3950.     if ((MDEFHandle != NULL) && (SICNHandle != NULL)) {
  3951.         HLock(MDEFHandle);
  3952.         menuDefProc = TkNewMenuDefProc(MenuDefProc);
  3953.         memmove((void *) (((long) (*MDEFHandle)) + 0x24), &menuDefProc, 4);
  3954.         HUnlock(MDEFHandle);
  3955.     }
  3956. #endif
  3957.  
  3958.     lastMenuID = 256;
  3959.     Tcl_InitHashTable(&commandTable, TCL_ONE_WORD_KEYS);
  3960.     currentMenuBarOwner = NULL;
  3961.     tearoffStruct.menuPtr = NULL;
  3962.     currentAppleMenuID = 0;
  3963.     currentHelpMenuID = 0;
  3964.     currentMenuBarInterp = NULL;
  3965.     currentMenuBarName = NULL;
  3966.     windowListPtr = NULL;
  3967. }
  3968.